[
  {
    "path": ".github/CONTRIBUTING.md",
    "content": "# Contributing to `TableView`\n\n## Table of contents\n\n- [I need help/I have a question](#i-need-helpi-have-a-question)\n- [Reporting a bug](#reporting-a-bug)\n- [Suggest a new feature](#suggest-a-new-feature)\n- [Contributing to the project](#contributing-to-the-project)\n\n## I need help/I have a question\n\nIf you need help to integrate this library in your project, or if you have a generic question about it, please use [Stack Overflow](https://stackoverflow.com/questions/tagged/tableview+android), with the `TableView` and `Android` tags.\n\n## Reporting a bug\n\nIf the library is not behaving as you would expect, please [open a new issue](https://github.com/evrencoskun/TableView/issues/new?labels=bug&template=bug_report.md), after checking that it hasn't been reported yet.\nDon't forget to provide as much information as you can:\n\n- What are you trying to do?\n- What happened instead?\n- In case of crash, include the stacktace.\n- Which version of the library are you using?\n- Which version of Android is this issue happening on?\n\n## Suggest a new feature\n\nIf you would like a new feature to be added to the library, please [open a new issue](https://github.com/evrencoskun/TableView/issues/new?labels=enhancement&template=feature_request.md) to describe it.\n\n## Contributing to the project\n\nEvery contribution is welcome to the library. Simply [open a new Pull Request](https://github.com/evrencoskun/TableView/compare) with your changes, so they can be reviewed and merged into the project, and eventually released to everyone.\n\nNote that by making a contribution to this project you are agreeing to have your contributions governed by the [MIT License](https://github.com/evrencoskun/TableView/blob/master/LICENSE) copyright statement.\nThis means that to the extent possible under law, you transfer all copyright and related or neighbouring rights of the code or documents you contribute to the project itself. You also represent that you have the authority to perform the above waiver with respect to the entirety of you contributions.\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]\npatreon: evrencoskun # Replace with a single Patreon username\nopen_collective: # Replace with a single Open Collective username\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\ncustom: ['https://www.paypal.me/evrencoshkun']\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Stacktrace**\nIf applicable, add the stacktrace you encountered.\n\n**Tools:**\n - `TableView` version: [e.g. 0.8.9.2]\n - Android version: [e.g. 11]\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "contact_links:\n  - name: Stack Overflow\n    url: https://stackoverflow.com/questions/tagged/tableview+android\n    about: Please ask your questions here, with the `TableView` and `Android` tags\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: enhancement\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/workflows/validate_tableview.yml",
    "content": "name: Validate TableView\n\non:\n  push:\n  pull_request:\n\njobs:\n  build:\n    name: Build\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v2\n\n      - name: Gradle Wrapper Validation\n        uses: gradle/wrapper-validation-action@v1\n\n      - name: Setup JDK 1.8\n        uses: actions/setup-java@v1\n        with:\n          java-version: 1.8\n\n      - name: Setup Cache\n        uses: actions/cache@v2\n        with:\n          path: |\n            ~/.gradle/caches/\n            ~/.gradle/wrapper/\n          key: cache-gradle-${{ hashFiles('**/*.gradle') }}\n          restore-keys: cache-gradle-\n\n      - name: Build\n        run: ./gradlew :tableview:assembleDebug --no-daemon\n\n  validate-sample:\n    name: Validate sample app\n    needs: build\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v2\n\n      - name: Setup JDK 1.8\n        uses: actions/setup-java@v1\n        with:\n          java-version: 1.8\n\n      - name: Setup Cache\n        uses: actions/cache@v2\n        with:\n          path: |\n            ~/.gradle/caches/\n            ~/.gradle/wrapper/\n          key: cache-gradle-${{ hashFiles('**/*.gradle') }}\n          restore-keys: cache-gradle-\n\n      - name: Build\n        run: ./gradlew :app:assembleDebug --no-daemon\n\n  android-tests:\n    name: Android Tests\n    needs: build\n    # Using macos-latest to take advantage of the hardware acceleration\n    runs-on: macos-latest\n    strategy:\n      matrix:\n        api-level: [ 15, 29 ]\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v2\n\n      - name: Setup JDK 1.8\n        uses: actions/setup-java@v1\n        with:\n          java-version: 1.8\n\n      - name: Setup Cache\n        uses: actions/cache@v2\n        with:\n          path: |\n            ~/.gradle/caches/\n            ~/.gradle/wrapper/\n          key: cache-gradle-${{ hashFiles('**/*.gradle') }}\n          restore-keys: cache-gradle-\n\n      - name: Android Test - API ${{ matrix.api-level }}\n        uses: ReactiveCircus/android-emulator-runner@v2\n        with:\n          api-level: ${{ matrix.api-level }}\n          script: ./gradlew :tableview:connectedDebugAndroidTest --no-daemon\n"
  },
  {
    "path": ".gitignore",
    "content": "# Built application files\n*.apk\n*.ap_\n\n# Mac\n.DS_Store\n\n# Files for the ART/Dalvik VM\n*.dex\n\n# Java class files\n*.class\n\n# Generated files\nbin/\ngen/\nout/\n\n# Gradle files\n.gradle/\nbuild/\n\n# Local configuration file (sdk path, etc)\nlocal.properties\n\n# Proguard folder generated by Eclipse\nproguard/\n\n# Log Files\n*.log\n\n# Android Studio Navigation editor temp files\n.navigation/\n\n# Android Studio captures folder\ncaptures/\n\n# Intellij\n*.iml\n*.idea/\n\n# Keystore files\n*.jks\n\n# External native build folder generated in Android Studio 2.2 and later\n.externalNativeBuild\n\n# Google Services (e.g. APIs or Firebase)\ngoogle-services.json\n\n# Freeline\nfreeline.py\nfreeline/\nfreeline_project_description.json\n\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 Evren Coşkun\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<div align=\"center\">\n    <img src=\"https://raw.githubusercontent.com/evrencoskun/TableViewSample/master/art/Logo-5.png\" >\n    <h2>TableView for Android</h2>\n    <p align=\"center\">\n        <p>TableView is a powerful Android library for displaying complex data structures and rendering tabular data composed of rows, columns and cells. \n           TableView relies on a separate model object to hold and represent the data it displays. This repository also contains a sample app that is\n           designed to show you how to create your own TableView in your application.</p>        \n        <a href=\"https://youtu.be/1DWFIqrqrPk\">\n            <b> Full video »</b>\n        </a>\n    </p>\n\n</div>\n\n<p align=\"center\">\n    <a href=\"https://youtu.be/1DWFIqrqrPk\">\n      <img src=\"https://raw.githubusercontent.com/evrencoskun/TableViewSample/master/art/TableView-0_8_5_1_2.gif\">\n    </a>\n</p>\n\n## Features\n\n  - [x] Each column width value can be calculated automatically considering the largest one.\n  - [x] Setting your own model class to be displayed in a table view easily.\n  - [x] `TableView` has an action listener interface to listen user touch interaction for each cell.\n  - [x] `TableView` columns can be sorted in ascending or descending order.\n  - [x] Hiding & showing the rows and columns is pretty easy.\n  - [x] Filtering by more than one data.\n  - [x] Pagination functionality.\n\n## What's new\n\nYou can check new implementations of `TableView` on the [release page](https://github.com/evrencoskun/TableView/releases).\n  \n## Table of Contents\n\n  - [Installation](#installation)\n  - [Documentation](#documentation)\n  - [Sample Apps](#sample-apps)\n  - [Donations](#donations)\n  - [Contributors](#contributors)\n  - [License](#license)\n\n## Installation\n\nTo use this library in your Android project, just add the following dependency into your module's `build.gradle`:\n\n***Use Jitpack implementation***\n\n1. Check Jitpack use : \n```\n\tallprojects {\n\t\trepositories {\n\t\t\t...\n\t\t\tmaven { url 'https://jitpack.io' }\n\t\t}\n\t}\n```\n\n2. Add implementation in project build :\n```\nimplementation 'com.github.evrencoskun:TableView:v0.8.9.4'\n```\n\n## Documentation \n\nPlease check out the [project's wiki](https://github.com/evrencoskun/TableView/wiki).\n\n## Sample Apps\n\n- This repository has a [sample application](https://github.com/evrencoskun/TableView/tree/master/app) of `TableView`.\n- [TableViewSample 2](https://github.com/evrencoskun/TableViewSample2)\n- [Xently-UI](https://github.com/ajharry69/Xently-UI)\n- [Price List Lite](https://pricelistlite.isolpro.in)\n- [Database Client for MySQL and PostgreSQL](https://play.google.com/store/apps/details?id=dev.dhruv.databaseclient)\n- ([Submit a Pull Request](https://github.com/evrencoskun/TableView/compare) to mention your app on this page)\n\n## Donations\n\n**This project needs you!** If you would like to support this project's further development, the creator of this project or the continuous maintenance of this project, **feel free to donate**. Your donation is highly appreciated (and I love food, coffee and beer). Thank you!\n\n**PayPal**\n\n- [**Donate 5 $**](https://www.paypal.me/evrencoshkun): Thank's for creating this project, here's a coffee (or some beer) for you!\n- [**Donate 10 $**](https://www.paypal.me/evrencoshkun): Wow, I am stunned. Let me take you to the movies!\n- [**Donate 15 $**](https://www.paypal.me/evrencoshkun): I really appreciate your work, let's grab some lunch!\n- [**Donate 25 $**](https://www.paypal.me/evrencoshkun): That's some awesome stuff you did right there, dinner is on me!\n- Or you can also [**choose what you want to donate**](https://www.paypal.me/evrencoshkun), all donations are awesome!\n\n## Contributors\n\nContributions of any kind are welcome! I would like to thank all the [contributors](https://github.com/evrencoskun/TableView/graphs/contributors) for sharing code and\nmaking `TableView` a better product.\n\nIf you wish to contribute to this project, please refer to our [contributing guide](.github/CONTRIBUTING.md).\n\n## License\n\n```\nMIT License\n\nCopyright (c) 2021 Evren Coşkun\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n```\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\napply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion compile_sdk_version\n\n    defaultConfig {\n        applicationId 'com.evrencoskun.tableviewsample'\n        minSdkVersion min_sdk_version\n        targetSdkVersion target_sdk_version\n        versionCode 1\n        versionName '1.0'\n        testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'\n        vectorDrawables.useSupportLibrary = true\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n\n    compileOptions {\n        sourceCompatibility = java_version\n        targetCompatibility = java_version\n    }\n\n    buildFeatures {\n        buildConfig = false\n    }\n\n    lintOptions {\n        abortOnError false\n    }\n}\n\ndependencies {\n    implementation project(path: ':tableview')\n\n    implementation \"androidx.annotation:annotation:$androidx_annotation_version\"\n    implementation \"androidx.appcompat:appcompat:$androidx_appcompat_version\"\n    implementation \"androidx.fragment:fragment:$androidx_fragment_version\"\n    implementation \"androidx.recyclerview:recyclerview:$androidx_recyclerview_version\"\n}\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /Users/evrencoskun/Library/Android/sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n ~ MIT License\n ~\n ~ Copyright (c) 2021 Evren Coşkun\n ~\n ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n ~ of this software and associated documentation files (the \"Software\"), to deal\n ~ in the Software without restriction, including without limitation the rights\n ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n ~ copies of the Software, and to permit persons to whom the Software is\n ~ furnished to do so, subject to the following conditions:\n ~\n ~ The above copyright notice and this permission notice shall be included in all\n ~ copies or substantial portions of the Software.\n ~\n ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n ~ SOFTWARE.\n  -->\n<manifest package=\"com.evrencoskun.tableviewsample\"\n          xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\">\n        <activity android:name=\".MainActivity\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\"/>\n\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n            </intent-filter>\n        </activity>\n    </application>\n\n</manifest>"
  },
  {
    "path": "app/src/main/java/com/evrencoskun/tableviewsample/MainActivity.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableviewsample;\n\nimport androidx.appcompat.app.AppCompatActivity;\n\npublic class MainActivity extends AppCompatActivity {\n    public MainActivity() {\n        super(R.layout.activity_main);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/evrencoskun/tableviewsample/MainFragment.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableviewsample;\n\nimport android.os.Bundle;\nimport android.text.Editable;\nimport android.text.TextUtils;\nimport android.text.TextWatcher;\nimport android.view.View;\nimport android.widget.AdapterView;\nimport android.widget.EditText;\nimport android.widget.ImageButton;\nimport android.widget.Spinner;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\n\nimport com.evrencoskun.tableview.TableView;\nimport com.evrencoskun.tableview.filter.Filter;\nimport com.evrencoskun.tableview.pagination.Pagination;\nimport com.evrencoskun.tableviewsample.tableview.TableViewAdapter;\nimport com.evrencoskun.tableviewsample.tableview.TableViewListener;\nimport com.evrencoskun.tableviewsample.tableview.TableViewModel;\n\n/**\n * A simple {@link Fragment} subclass.\n */\npublic class MainFragment extends Fragment {\n    private Spinner moodFilter, genderFilter;\n    private ImageButton previousButton, nextButton;\n    private TextView tablePaginationDetails;\n    private TableView mTableView;\n    @Nullable\n    private Filter mTableFilter; // This is used for filtering the table.\n    @Nullable\n    private Pagination mPagination; // This is used for paginating the table.\n\n    private boolean mPaginationEnabled = false;\n\n    public MainFragment() {\n        super(R.layout.fragment_main);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        EditText searchField = view.findViewById(R.id.query_string);\n        searchField.addTextChangedListener(mSearchTextWatcher);\n\n        moodFilter = view.findViewById(R.id.mood_spinner);\n        moodFilter.setOnItemSelectedListener(mItemSelectionListener);\n\n        genderFilter = view.findViewById(R.id.gender_spinner);\n        genderFilter.setOnItemSelectedListener(mItemSelectionListener);\n\n        Spinner itemsPerPage = view.findViewById(R.id.items_per_page_spinner);\n\n        View tableTestContainer = view.findViewById(R.id.table_test_container);\n\n        previousButton = view.findViewById(R.id.previous_button);\n        nextButton = view.findViewById(R.id.next_button);\n        EditText pageNumberField = view.findViewById(R.id.page_number_text);\n        tablePaginationDetails = view.findViewById(R.id.table_details);\n\n        if (mPaginationEnabled) {\n            tableTestContainer.setVisibility(View.VISIBLE);\n            itemsPerPage.setOnItemSelectedListener(onItemsPerPageSelectedListener);\n\n            previousButton.setOnClickListener(mClickListener);\n            nextButton.setOnClickListener(mClickListener);\n            pageNumberField.addTextChangedListener(onPageTextChanged);\n        } else {\n            tableTestContainer.setVisibility(View.GONE);\n        }\n\n        // Let's get TableView\n        mTableView = view.findViewById(R.id.tableview);\n\n        initializeTableView();\n\n        if (mPaginationEnabled) {\n            mTableFilter = new Filter(mTableView); // Create an instance of a Filter and pass the\n            // created TableView.\n\n            // Create an instance for the TableView pagination and pass the created TableView.\n            mPagination = new Pagination(mTableView);\n\n            // Sets the pagination listener of the TableView pagination to handle\n            // pagination actions. See onTableViewPageTurnedListener variable declaration below.\n            mPagination.setOnTableViewPageTurnedListener(onTableViewPageTurnedListener);\n        }\n    }\n\n    private void initializeTableView() {\n        // Create TableView View model class  to group view models of TableView\n        TableViewModel tableViewModel = new TableViewModel();\n\n        // Create TableView Adapter\n        TableViewAdapter tableViewAdapter = new TableViewAdapter(tableViewModel);\n\n        mTableView.setAdapter(tableViewAdapter);\n        mTableView.setTableViewListener(new TableViewListener(mTableView));\n\n        // Create an instance of a Filter and pass the TableView.\n        //mTableFilter = new Filter(mTableView);\n\n        // Load the dummy data to the TableView\n        tableViewAdapter.setAllItems(tableViewModel.getColumnHeaderList(), tableViewModel\n                .getRowHeaderList(), tableViewModel.getCellList());\n\n        //mTableView.setHasFixedWidth(true);\n\n        /*for (int i = 0; i < mTableViewModel.getCellList().size(); i++) {\n            mTableView.setColumnWidth(i, 200);\n        }*)\n\n        //mTableView.setColumnWidth(0, -2);\n        //mTableView.setColumnWidth(1, -2);\n\n        /*mTableView.setColumnWidth(2, 200);\n        mTableView.setColumnWidth(3, 300);\n        mTableView.setColumnWidth(4, 400);\n        mTableView.setColumnWidth(5, 500);*/\n\n    }\n\n    public void filterTable(@NonNull String filter) {\n        // Sets a filter to the table, this will filter ALL the columns.\n        if (mTableFilter != null) {\n            mTableFilter.set(filter);\n        }\n    }\n\n    public void filterTableForMood(@NonNull String filter) {\n        // Sets a filter to the table, this will only filter a specific column.\n        // In the example data, this will filter the mood column.\n        if (mTableFilter != null) {\n            mTableFilter.set(TableViewModel.MOOD_COLUMN_INDEX, filter);\n        }\n    }\n\n    public void filterTableForGender(@NonNull String filter) {\n        // Sets a filter to the table, this will only filter a specific column.\n        // In the example data, this will filter the gender column.\n        if (mTableFilter != null) {\n            mTableFilter.set(TableViewModel.GENDER_COLUMN_INDEX, filter);\n        }\n    }\n\n    // The following four methods below: nextTablePage(), previousTablePage(),\n    // goToTablePage(int page) and setTableItemsPerPage(int itemsPerPage)\n    // are for controlling the TableView pagination.\n    public void nextTablePage() {\n        if (mPagination != null) {\n            mPagination.nextPage();\n        }\n    }\n\n    public void previousTablePage() {\n        if (mPagination != null) {\n            mPagination.previousPage();\n        }\n    }\n\n    public void goToTablePage(int page) {\n        if (mPagination != null) {\n            mPagination.goToPage(page);\n        }\n    }\n\n    public void setTableItemsPerPage(int itemsPerPage) {\n        if (mPagination != null) {\n            mPagination.setItemsPerPage(itemsPerPage);\n        }\n    }\n\n    // Handler for the changing of pages in the paginated TableView.\n    @NonNull\n    private final Pagination.OnTableViewPageTurnedListener onTableViewPageTurnedListener = new\n            Pagination.OnTableViewPageTurnedListener() {\n                @Override\n                public void onPageTurned(int numItems, int itemsStart, int itemsEnd) {\n                    int currentPage = mPagination.getCurrentPage();\n                    int pageCount = mPagination.getPageCount();\n                    previousButton.setVisibility(View.VISIBLE);\n                    nextButton.setVisibility(View.VISIBLE);\n\n                    if (currentPage == 1 && pageCount == 1) {\n                        previousButton.setVisibility(View.INVISIBLE);\n                        nextButton.setVisibility(View.INVISIBLE);\n                    }\n\n                    if (currentPage == 1) {\n                        previousButton.setVisibility(View.INVISIBLE);\n                    }\n\n                    if (currentPage == pageCount) {\n                        nextButton.setVisibility(View.INVISIBLE);\n                    }\n\n                    tablePaginationDetails.setText(getString(R.string.table_pagination_details, String\n                            .valueOf(currentPage), String.valueOf(itemsStart), String.valueOf(itemsEnd)));\n\n                }\n            };\n\n    @NonNull\n    private final AdapterView.OnItemSelectedListener mItemSelectionListener = new AdapterView\n            .OnItemSelectedListener() {\n        @Override\n        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {\n            // 0. index is for empty item of spinner.\n            if (position > 0) {\n\n                String filter = Integer.toString(position);\n\n                if (parent == moodFilter) {\n                    filterTableForMood(filter);\n                } else if (parent == genderFilter) {\n                    filterTableForGender(filter);\n                }\n            }\n        }\n\n        @Override\n        public void onNothingSelected(AdapterView<?> parent) {\n            // Left empty intentionally.\n        }\n    };\n\n    @NonNull\n    private final TextWatcher mSearchTextWatcher = new TextWatcher() {\n        @Override\n        public void beforeTextChanged(CharSequence s, int start, int count, int after) {\n        }\n\n        @Override\n        public void onTextChanged(CharSequence s, int start, int before, int count) {\n            filterTable(String.valueOf(s));\n        }\n\n        @Override\n        public void afterTextChanged(Editable s) {\n        }\n    };\n\n    @NonNull\n    private final AdapterView.OnItemSelectedListener onItemsPerPageSelectedListener = new AdapterView\n            .OnItemSelectedListener() {\n        @Override\n        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {\n            int itemsPerPage;\n            if (\"All\".equals(parent.getItemAtPosition(position).toString())) {\n                itemsPerPage = 0;\n            } else {\n                itemsPerPage = Integer.parseInt(parent.getItemAtPosition(position).toString());\n            }\n\n            setTableItemsPerPage(itemsPerPage);\n        }\n\n        @Override\n        public void onNothingSelected(AdapterView<?> parent) {\n        }\n    };\n\n    @NonNull\n    private final View.OnClickListener mClickListener = new View.OnClickListener() {\n        @Override\n        public void onClick(View v) {\n            if (v == previousButton) {\n                previousTablePage();\n            } else if (v == nextButton) {\n                nextTablePage();\n            }\n        }\n    };\n\n    @NonNull\n    private final TextWatcher onPageTextChanged = new TextWatcher() {\n        @Override\n        public void beforeTextChanged(CharSequence s, int start, int count, int after) {\n        }\n\n        @Override\n        public void onTextChanged(CharSequence s, int start, int before, int count) {\n            int page;\n            if (TextUtils.isEmpty(s)) {\n                page = 1;\n            } else {\n                page = Integer.parseInt(String.valueOf(s));\n            }\n\n            goToTablePage(page);\n        }\n\n        @Override\n        public void afterTextChanged(Editable s) {\n        }\n    };\n}\n"
  },
  {
    "path": "app/src/main/java/com/evrencoskun/tableviewsample/tableview/TableViewAdapter.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableviewsample.tableview;\n\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.evrencoskun.tableview.adapter.AbstractTableAdapter;\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder;\nimport com.evrencoskun.tableview.sort.SortState;\nimport com.evrencoskun.tableviewsample.R;\nimport com.evrencoskun.tableviewsample.tableview.holder.CellViewHolder;\nimport com.evrencoskun.tableviewsample.tableview.holder.ColumnHeaderViewHolder;\nimport com.evrencoskun.tableviewsample.tableview.holder.GenderCellViewHolder;\nimport com.evrencoskun.tableviewsample.tableview.holder.MoodCellViewHolder;\nimport com.evrencoskun.tableviewsample.tableview.holder.RowHeaderViewHolder;\nimport com.evrencoskun.tableviewsample.tableview.model.Cell;\nimport com.evrencoskun.tableviewsample.tableview.model.ColumnHeader;\nimport com.evrencoskun.tableviewsample.tableview.model.RowHeader;\n\n/**\n * Created by evrencoskun on 11/06/2017.\n * <p>\n * This is a sample of custom TableView Adapter.\n */\n\npublic class TableViewAdapter extends AbstractTableAdapter<ColumnHeader, RowHeader, Cell> {\n\n    // Cell View Types by Column Position\n    private static final int MOOD_CELL_TYPE = 1;\n    private static final int GENDER_CELL_TYPE = 2;\n    // add new one if it necessary..\n\n    private static final String LOG_TAG = TableViewAdapter.class.getSimpleName();\n\n    @NonNull\n    private final TableViewModel mTableViewModel;\n\n    public TableViewAdapter(@NonNull TableViewModel tableViewModel) {\n        super();\n        this.mTableViewModel = tableViewModel;\n    }\n\n    /**\n     * This is where you create your custom Cell ViewHolder. This method is called when Cell\n     * RecyclerView of the TableView needs a new RecyclerView.ViewHolder of the given type to\n     * represent an item.\n     *\n     * @param viewType : This value comes from \"getCellItemViewType\" method to support different\n     *                 type of viewHolder as a Cell item.\n     * @see #getCellItemViewType(int);\n     */\n    @NonNull\n    @Override\n    public AbstractViewHolder onCreateCellViewHolder(@NonNull ViewGroup parent, int viewType) {\n        //TODO check\n        Log.e(LOG_TAG, \" onCreateCellViewHolder has been called\");\n        LayoutInflater inflater = LayoutInflater.from(parent.getContext());\n        View layout;\n\n        switch (viewType) {\n            case MOOD_CELL_TYPE:\n                // Get image cell layout which has ImageView on the base instead of TextView.\n                layout = inflater.inflate(R.layout.table_view_image_cell_layout, parent, false);\n\n                return new MoodCellViewHolder(layout);\n            case GENDER_CELL_TYPE:\n                // Get image cell layout which has ImageView instead of TextView.\n                layout = inflater.inflate(R.layout.table_view_image_cell_layout, parent, false);\n\n                return new GenderCellViewHolder(layout);\n            default:\n                // For cells that display a text\n                layout = inflater.inflate(R.layout.table_view_cell_layout, parent, false);\n\n                // Create a Cell ViewHolder\n                return new CellViewHolder(layout);\n        }\n    }\n\n    /**\n     * That is where you set Cell View Model data to your custom Cell ViewHolder. This method is\n     * Called by Cell RecyclerView of the TableView to display the data at the specified position.\n     * This method gives you everything you need about a cell item.\n     *\n     * @param holder         : This is one of your cell ViewHolders that was created on\n     *                       ```onCreateCellViewHolder``` method. In this example we have created\n     *                       \"CellViewHolder\" holder.\n     * @param cellItemModel  : This is the cell view model located on this X and Y position. In this\n     *                       example, the model class is \"Cell\".\n     * @param columnPosition : This is the X (Column) position of the cell item.\n     * @param rowPosition    : This is the Y (Row) position of the cell item.\n     * @see #onCreateCellViewHolder(ViewGroup, int) ;\n     */\n    @Override\n    public void onBindCellViewHolder(@NonNull AbstractViewHolder holder, @Nullable Cell cellItemModel, int\n            columnPosition, int rowPosition) {\n\n        switch (holder.getItemViewType()) {\n            case MOOD_CELL_TYPE:\n                MoodCellViewHolder moodViewHolder = (MoodCellViewHolder) holder;\n\n                moodViewHolder.cell_image.setImageResource(mTableViewModel.getDrawable((int) cellItemModel\n                        .getData(), false));\n                break;\n            case GENDER_CELL_TYPE:\n                GenderCellViewHolder genderViewHolder = (GenderCellViewHolder) holder;\n\n                genderViewHolder.cell_image.setImageResource(mTableViewModel.getDrawable((int)\n                        cellItemModel.getData(), true));\n                break;\n            default:\n                // Get the holder to update cell item text\n                CellViewHolder viewHolder = (CellViewHolder) holder;\n                viewHolder.setCell(cellItemModel);\n                break;\n        }\n    }\n\n    /**\n     * This is where you create your custom Column Header ViewHolder. This method is called when\n     * Column Header RecyclerView of the TableView needs a new RecyclerView.ViewHolder of the given\n     * type to represent an item.\n     *\n     * @param viewType : This value comes from \"getColumnHeaderItemViewType\" method to support\n     *                 different type of viewHolder as a Column Header item.\n     * @see #getColumnHeaderItemViewType(int);\n     */\n    @NonNull\n    @Override\n    public AbstractViewHolder onCreateColumnHeaderViewHolder(@NonNull ViewGroup parent, int viewType) {\n        // TODO: check\n        //Log.e(LOG_TAG, \" onCreateColumnHeaderViewHolder has been called\");\n        // Get Column Header xml Layout\n        View layout = LayoutInflater.from(parent.getContext())\n                .inflate(R.layout.table_view_column_header_layout, parent, false);\n\n        // Create a ColumnHeader ViewHolder\n        return new ColumnHeaderViewHolder(layout, getTableView());\n    }\n\n    /**\n     * That is where you set Column Header View Model data to your custom Column Header ViewHolder.\n     * This method is Called by ColumnHeader RecyclerView of the TableView to display the data at\n     * the specified position. This method gives you everything you need about a column header\n     * item.\n     *\n     * @param holder                : This is one of your column header ViewHolders that was created\n     *                              on ```onCreateColumnHeaderViewHolder``` method. In this example\n     *                              we have created \"ColumnHeaderViewHolder\" holder.\n     * @param columnHeaderItemModel : This is the column header view model located on this X\n     *                              position. In this example, the model class is \"ColumnHeader\".\n     * @param columnPosition        : This is the X (Column) position of the column header item.\n     * @see #onCreateColumnHeaderViewHolder(ViewGroup, int) ;\n     */\n    @Override\n    public void onBindColumnHeaderViewHolder(@NonNull AbstractViewHolder holder, @Nullable ColumnHeader\n            columnHeaderItemModel, int columnPosition) {\n\n        // Get the holder to update cell item text\n        ColumnHeaderViewHolder columnHeaderViewHolder = (ColumnHeaderViewHolder) holder;\n        columnHeaderViewHolder.setColumnHeader(columnHeaderItemModel);\n    }\n\n    /**\n     * This is where you create your custom Row Header ViewHolder. This method is called when\n     * Row Header RecyclerView of the TableView needs a new RecyclerView.ViewHolder of the given\n     * type to represent an item.\n     *\n     * @param viewType : This value comes from \"getRowHeaderItemViewType\" method to support\n     *                 different type of viewHolder as a row Header item.\n     * @see #getRowHeaderItemViewType(int);\n     */\n    @NonNull\n    @Override\n    public AbstractViewHolder onCreateRowHeaderViewHolder(@NonNull ViewGroup parent, int viewType) {\n        // Get Row Header xml Layout\n        View layout = LayoutInflater.from(parent.getContext())\n                .inflate(R.layout.table_view_row_header_layout, parent, false);\n\n        // Create a Row Header ViewHolder\n        return new RowHeaderViewHolder(layout);\n    }\n\n\n    /**\n     * That is where you set Row Header View Model data to your custom Row Header ViewHolder. This\n     * method is Called by RowHeader RecyclerView of the TableView to display the data at the\n     * specified position. This method gives you everything you need about a row header item.\n     *\n     * @param holder             : This is one of your row header ViewHolders that was created on\n     *                           ```onCreateRowHeaderViewHolder``` method. In this example we have\n     *                           created \"RowHeaderViewHolder\" holder.\n     * @param rowHeaderItemModel : This is the row header view model located on this Y position. In\n     *                           this example, the model class is \"RowHeader\".\n     * @param rowPosition        : This is the Y (row) position of the row header item.\n     * @see #onCreateRowHeaderViewHolder(ViewGroup, int) ;\n     */\n    @Override\n    public void onBindRowHeaderViewHolder(@NonNull AbstractViewHolder holder, @Nullable RowHeader rowHeaderItemModel,\n                                          int rowPosition) {\n\n        // Get the holder to update row header item text\n        RowHeaderViewHolder rowHeaderViewHolder = (RowHeaderViewHolder) holder;\n        rowHeaderViewHolder.row_header_textview.setText(String.valueOf(rowHeaderItemModel.getData()));\n    }\n\n    @NonNull\n    @Override\n    public View onCreateCornerView(@NonNull ViewGroup parent) {\n        // Get Corner xml layout\n        View corner = LayoutInflater.from(parent.getContext())\n                .inflate(R.layout.table_view_corner_layout, parent, false);\n        corner.setOnClickListener(view -> {\n            SortState sortState = TableViewAdapter.this.getTableView()\n                    .getRowHeaderSortingStatus();\n            if (sortState != SortState.ASCENDING) {\n                Log.d(\"TableViewAdapter\", \"Order Ascending\");\n                TableViewAdapter.this.getTableView().sortRowHeader(SortState.ASCENDING);\n            } else {\n                Log.d(\"TableViewAdapter\", \"Order Descending\");\n                TableViewAdapter.this.getTableView().sortRowHeader(SortState.DESCENDING);\n            }\n        });\n        return corner;\n    }\n\n    @Override\n    public int getColumnHeaderItemViewType(int position) {\n        // The unique ID for this type of column header item\n        // If you have different items for Cell View by X (Column) position,\n        // then you should fill this method to be able create different\n        // type of CellViewHolder on \"onCreateCellViewHolder\"\n        return 0;\n    }\n\n    @Override\n    public int getRowHeaderItemViewType(int position) {\n        // The unique ID for this type of row header item\n        // If you have different items for Row Header View by Y (Row) position,\n        // then you should fill this method to be able create different\n        // type of RowHeaderViewHolder on \"onCreateRowHeaderViewHolder\"\n        return 0;\n    }\n\n    @Override\n    public int getCellItemViewType(int column) {\n\n        // The unique ID for this type of cell item\n        // If you have different items for Cell View by X (Column) position,\n        // then you should fill this method to be able create different\n        // type of CellViewHolder on \"onCreateCellViewHolder\"\n        switch (column) {\n            case TableViewModel.MOOD_COLUMN_INDEX:\n                return MOOD_CELL_TYPE;\n            case TableViewModel.GENDER_COLUMN_INDEX:\n                return GENDER_CELL_TYPE;\n            default:\n                // Default view type\n                return 0;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/evrencoskun/tableviewsample/tableview/TableViewListener.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableviewsample.tableview;\n\nimport android.content.Context;\nimport android.widget.Toast;\n\nimport androidx.annotation.NonNull;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.evrencoskun.tableview.TableView;\nimport com.evrencoskun.tableview.listener.ITableViewListener;\nimport com.evrencoskun.tableviewsample.tableview.holder.ColumnHeaderViewHolder;\nimport com.evrencoskun.tableviewsample.tableview.popup.ColumnHeaderLongPressPopup;\nimport com.evrencoskun.tableviewsample.tableview.popup.RowHeaderLongPressPopup;\n\n/**\n * Created by evrencoskun on 21/09/2017.\n */\n\npublic class TableViewListener implements ITableViewListener {\n    @NonNull\n    private final Context mContext;\n    @NonNull\n    private final TableView mTableView;\n\n    public TableViewListener(@NonNull TableView tableView) {\n        this.mContext = tableView.getContext();\n        this.mTableView = tableView;\n    }\n\n    /**\n     * Called when user click any cell item.\n     *\n     * @param cellView : Clicked Cell ViewHolder.\n     * @param column   : X (Column) position of Clicked Cell item.\n     * @param row      : Y (Row) position of Clicked Cell item.\n     */\n    @Override\n    public void onCellClicked(@NonNull RecyclerView.ViewHolder cellView, int column, int row) {\n\n        // Do what you want.\n        showToast(\"Cell \" + column + \" \" + row + \" has been clicked.\");\n\n    }\n\n    /**\n     * Called when user double click any cell item.\n     *\n     * @param cellView : Clicked Cell ViewHolder.\n     * @param column   : X (Column) position of Clicked Cell item.\n     * @param row      : Y (Row) position of Clicked Cell item.\n     */\n    @Override\n    public void onCellDoubleClicked(@NonNull RecyclerView.ViewHolder cellView, int column, int row) {\n        // Do what you want.\n        showToast(\"Cell \" + column + \" \" + row + \" has been double clicked.\");\n    }\n\n    /**\n     * Called when user long press any cell item.\n     *\n     * @param cellView : Long Pressed Cell ViewHolder.\n     * @param column   : X (Column) position of Long Pressed Cell item.\n     * @param row      : Y (Row) position of Long Pressed Cell item.\n     */\n    @Override\n    public void onCellLongPressed(@NonNull RecyclerView.ViewHolder cellView, final int column,\n                                  int row) {\n        // Do What you want\n        showToast(\"Cell \" + column + \" \" + row + \" has been long pressed.\");\n    }\n\n    /**\n     * Called when user click any column header item.\n     *\n     * @param columnHeaderView : Clicked Column Header ViewHolder.\n     * @param column           : X (Column) position of Clicked Column Header item.\n     */\n    @Override\n    public void onColumnHeaderClicked(@NonNull RecyclerView.ViewHolder columnHeaderView, int\n            column) {\n        // Do what you want.\n        showToast(\"Column header  \" + column + \" has been clicked.\");\n    }\n\n    /**\n     * Called when user double click any column header item.\n     *\n     * @param columnHeaderView : Clicked Column Header ViewHolder.\n     * @param column           : X (Column) position of Clicked Column Header item.\n     */\n    @Override\n    public void onColumnHeaderDoubleClicked(@NonNull RecyclerView.ViewHolder columnHeaderView, int column) {\n        // Do what you want.\n        showToast(\"Column header  \" + column + \" has been double clicked.\");\n    }\n\n    /**\n     * Called when user long press any column header item.\n     *\n     * @param columnHeaderView : Long Pressed Column Header ViewHolder.\n     * @param column           : X (Column) position of Long Pressed Column Header item.\n     */\n    @Override\n    public void onColumnHeaderLongPressed(@NonNull RecyclerView.ViewHolder columnHeaderView, int\n            column) {\n\n        if (columnHeaderView instanceof ColumnHeaderViewHolder) {\n            // Create Long Press Popup\n            ColumnHeaderLongPressPopup popup = new ColumnHeaderLongPressPopup(\n                    (ColumnHeaderViewHolder) columnHeaderView, mTableView);\n            // Show\n            popup.show();\n        }\n    }\n\n    /**\n     * Called when user click any Row Header item.\n     *\n     * @param rowHeaderView : Clicked Row Header ViewHolder.\n     * @param row           : Y (Row) position of Clicked Row Header item.\n     */\n    @Override\n    public void onRowHeaderClicked(@NonNull RecyclerView.ViewHolder rowHeaderView, int row) {\n        // Do whatever you want.\n        showToast(\"Row header \" + row + \" has been clicked.\");\n    }\n\n    /**\n     * Called when user double click any Row Header item.\n     *\n     * @param rowHeaderView : Clicked Row Header ViewHolder.\n     * @param row           : Y (Row) position of Clicked Row Header item.\n     */\n    @Override\n    public void onRowHeaderDoubleClicked(@NonNull RecyclerView.ViewHolder rowHeaderView, int row) {\n        // Do whatever you want.\n        showToast(\"Row header \" + row + \" has been double clicked.\");\n    }\n\n    /**\n     * Called when user long press any row header item.\n     *\n     * @param rowHeaderView : Long Pressed Row Header ViewHolder.\n     * @param row           : Y (Row) position of Long Pressed Row Header item.\n     */\n    @Override\n    public void onRowHeaderLongPressed(@NonNull RecyclerView.ViewHolder rowHeaderView, int row) {\n\n        // Create Long Press Popup\n        RowHeaderLongPressPopup popup = new RowHeaderLongPressPopup(rowHeaderView, mTableView);\n        // Show\n        popup.show();\n    }\n\n\n    private void showToast(String p_strMessage) {\n        Toast.makeText(mContext, p_strMessage, Toast.LENGTH_SHORT).show();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/evrencoskun/tableviewsample/tableview/TableViewModel.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableviewsample.tableview;\n\nimport androidx.annotation.DrawableRes;\nimport androidx.annotation.NonNull;\n\nimport com.evrencoskun.tableviewsample.R;\nimport com.evrencoskun.tableviewsample.tableview.model.Cell;\nimport com.evrencoskun.tableviewsample.tableview.model.ColumnHeader;\nimport com.evrencoskun.tableviewsample.tableview.model.RowHeader;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Random;\n\n/**\n * Created by evrencoskun on 4.02.2018.\n */\n\npublic class TableViewModel {\n\n    // Columns indexes\n    public static final int MOOD_COLUMN_INDEX = 3;\n    public static final int GENDER_COLUMN_INDEX = 4;\n\n    // Constant values for icons\n    public static final int SAD = 1;\n    public static final int HAPPY = 2;\n    public static final int BOY = 1;\n    public static final int GIRL = 2;\n\n    // Constant size for dummy data sets\n    private static final int COLUMN_SIZE = 500;\n    private static final int ROW_SIZE = 500;\n\n    // Drawables\n    @DrawableRes\n    private final int mBoyDrawable;\n    @DrawableRes\n    private final int mGirlDrawable;\n    @DrawableRes\n    private final int mHappyDrawable;\n    @DrawableRes\n    private final int mSadDrawable;\n\n    public TableViewModel() {\n        // initialize drawables\n        mBoyDrawable = R.drawable.ic_male;\n        mGirlDrawable = R.drawable.ic_female;\n        mHappyDrawable = R.drawable.ic_happy;\n        mSadDrawable = R.drawable.ic_sad;\n    }\n\n    @NonNull\n    private List<RowHeader> getSimpleRowHeaderList() {\n        List<RowHeader> list = new ArrayList<>();\n        for (int i = 0; i < ROW_SIZE; i++) {\n            RowHeader header = new RowHeader(String.valueOf(i), \"row \" + i);\n            list.add(header);\n        }\n\n        return list;\n    }\n\n    /**\n     * This is a dummy model list test some cases.\n     */\n    @NonNull\n    private List<ColumnHeader> getRandomColumnHeaderList() {\n        List<ColumnHeader> list = new ArrayList<>();\n\n        for (int i = 0; i < COLUMN_SIZE; i++) {\n            String title = \"column \" + i;\n            int nRandom = new Random().nextInt();\n            if (nRandom % 4 == 0 || nRandom % 3 == 0 || nRandom == i) {\n                title = \"large column \" + i;\n            }\n\n            ColumnHeader header = new ColumnHeader(String.valueOf(i), title);\n            list.add(header);\n        }\n\n        return list;\n    }\n\n    /**\n     * This is a dummy model list test some cases.\n     */\n    @NonNull\n    private List<List<Cell>> getCellListForSortingTest() {\n        List<List<Cell>> list = new ArrayList<>();\n        for (int i = 0; i < ROW_SIZE; i++) {\n            List<Cell> cellList = new ArrayList<>();\n            for (int j = 0; j < COLUMN_SIZE; j++) {\n                Object text = \"cell \" + j + \" \" + i;\n\n                final int random = new Random().nextInt();\n                if (j == 0) {\n                    text = i;\n                } else if (j == 1) {\n                    text = random;\n                } else if (j == MOOD_COLUMN_INDEX) {\n                    text = random % 2 == 0 ? HAPPY : SAD;\n                } else if (j == GENDER_COLUMN_INDEX) {\n                    text = random % 2 == 0 ? BOY : GIRL;\n                }\n\n                // Create dummy id.\n                String id = j + \"-\" + i;\n\n                Cell cell;\n                if (j == 3) {\n                    cell = new Cell(id, text);\n                } else if (j == 4) {\n                    // NOTE female and male keywords for filter will have conflict since \"female\"\n                    // contains \"male\"\n                    cell = new Cell(id, text);\n                } else {\n                    cell = new Cell(id, text);\n                }\n                cellList.add(cell);\n            }\n            list.add(cellList);\n        }\n\n        return list;\n    }\n\n    @DrawableRes\n    public int getDrawable(int value, boolean isGender) {\n        if (isGender) {\n            return value == BOY ? mBoyDrawable : mGirlDrawable;\n        } else {\n            return value == SAD ? mSadDrawable : mHappyDrawable;\n        }\n    }\n\n    @NonNull\n    public List<List<Cell>> getCellList() {\n        return getCellListForSortingTest();\n    }\n\n    @NonNull\n    public List<RowHeader> getRowHeaderList() {\n        return getSimpleRowHeaderList();\n    }\n\n    @NonNull\n    public List<ColumnHeader> getColumnHeaderList() {\n        return getRandomColumnHeaderList();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/evrencoskun/tableviewsample/tableview/holder/CellViewHolder.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableviewsample.tableview.holder;\n\nimport android.view.View;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder;\nimport com.evrencoskun.tableviewsample.R;\nimport com.evrencoskun.tableviewsample.tableview.model.Cell;\n\n/**\n * Created by evrencoskun on 23/10/2017.\n */\n\npublic class CellViewHolder extends AbstractViewHolder {\n    @NonNull\n    private final TextView cell_textview;\n    @NonNull\n    private final LinearLayout cell_container;\n\n    public CellViewHolder(@NonNull View itemView) {\n        super(itemView);\n        cell_textview = itemView.findViewById(R.id.cell_data);\n        cell_container = itemView.findViewById(R.id.cell_container);\n    }\n\n    public void setCell(@Nullable Cell cell) {\n        cell_textview.setText(String.valueOf(cell.getData()));\n\n        // If your TableView should have auto resize for cells & columns.\n        // Then you should consider the below lines. Otherwise, you can ignore them.\n\n        // It is necessary to remeasure itself.\n        cell_container.getLayoutParams().width = LinearLayout.LayoutParams.WRAP_CONTENT;\n        cell_textview.requestLayout();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/evrencoskun/tableviewsample/tableview/holder/ColumnHeaderViewHolder.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableviewsample.tableview.holder;\n\nimport android.util.Log;\nimport android.view.View;\nimport android.widget.ImageButton;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.evrencoskun.tableview.ITableView;\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractSorterViewHolder;\nimport com.evrencoskun.tableview.sort.SortState;\nimport com.evrencoskun.tableviewsample.R;\nimport com.evrencoskun.tableviewsample.tableview.model.ColumnHeader;\n\n/**\n * Created by evrencoskun on 23/10/2017.\n */\n\npublic class ColumnHeaderViewHolder extends AbstractSorterViewHolder {\n\n    private static final String LOG_TAG = ColumnHeaderViewHolder.class.getSimpleName();\n\n    @NonNull\n    private final LinearLayout column_header_container;\n    @NonNull\n    private final TextView column_header_textview;\n    @NonNull\n    private final ImageButton column_header_sortButton;\n    @Nullable\n    private final ITableView tableView;\n\n    public ColumnHeaderViewHolder(@NonNull View itemView, @Nullable ITableView tableView) {\n        super(itemView);\n        this.tableView = tableView;\n        column_header_textview = itemView.findViewById(R.id.column_header_textView);\n        column_header_container = itemView.findViewById(R.id.column_header_container);\n        column_header_sortButton = itemView.findViewById(R.id.column_header_sortButton);\n\n        // Set click listener to the sort button\n        column_header_sortButton.setOnClickListener(mSortButtonClickListener);\n    }\n\n    /**\n     * This method is calling from onBindColumnHeaderHolder on TableViewAdapter\n     */\n    public void setColumnHeader(@Nullable ColumnHeader columnHeader) {\n        column_header_textview.setText(String.valueOf(columnHeader.getData()));\n\n        // If your TableView should have auto resize for cells & columns.\n        // Then you should consider the below lines. Otherwise, you can remove them.\n\n        // It is necessary to remeasure itself.\n        column_header_container.getLayoutParams().width = LinearLayout.LayoutParams.WRAP_CONTENT;\n        column_header_textview.requestLayout();\n    }\n\n    @NonNull\n    private final View.OnClickListener mSortButtonClickListener = new View.OnClickListener() {\n        @Override\n        public void onClick(View view) {\n            if (getSortState() == SortState.ASCENDING) {\n                tableView.sortColumn(getBindingAdapterPosition(), SortState.DESCENDING);\n            } else if (getSortState() == SortState.DESCENDING) {\n                tableView.sortColumn(getBindingAdapterPosition(), SortState.ASCENDING);\n            } else {\n                // Default one\n                tableView.sortColumn(getBindingAdapterPosition(), SortState.DESCENDING);\n            }\n\n        }\n    };\n\n    @Override\n    public void onSortingStatusChanged(@NonNull SortState sortState) {\n        Log.e(LOG_TAG, \" + onSortingStatusChanged: x:  \" + getBindingAdapterPosition() + \", \" +\n                \"old state: \" + getSortState() + \", current state: \" + sortState + \", \" +\n                \"visibility: \" + column_header_sortButton.getVisibility());\n\n        super.onSortingStatusChanged(sortState);\n\n        // It is necessary to remeasure itself.\n        column_header_container.getLayoutParams().width = LinearLayout.LayoutParams.WRAP_CONTENT;\n\n        controlSortState(sortState);\n\n        Log.e(LOG_TAG, \" - onSortingStatusChanged: x:  \" + getBindingAdapterPosition() + \", \" +\n                \"old state: \" + getSortState() + \", current state: \" + sortState + \", \" +\n                \"visibility: \" + column_header_sortButton.getVisibility());\n\n        column_header_textview.requestLayout();\n        column_header_sortButton.requestLayout();\n        column_header_container.requestLayout();\n        itemView.requestLayout();\n    }\n\n    private void controlSortState(@NonNull SortState sortState) {\n        if (sortState == SortState.ASCENDING) {\n            column_header_sortButton.setVisibility(View.VISIBLE);\n            column_header_sortButton.setImageResource(R.drawable.ic_down);\n\n        } else if (sortState == SortState.DESCENDING) {\n            column_header_sortButton.setVisibility(View.VISIBLE);\n            column_header_sortButton.setImageResource(R.drawable.ic_up);\n        } else {\n            column_header_sortButton.setVisibility(View.INVISIBLE);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/evrencoskun/tableviewsample/tableview/holder/GenderCellViewHolder.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableviewsample.tableview.holder;\n\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\n\nimport com.evrencoskun.tableviewsample.R;\nimport com.evrencoskun.tableviewsample.tableview.TableViewModel;\n\n/**\n * Created by evrencoskun on 4.02.2018.\n */\n\npublic class GenderCellViewHolder extends MoodCellViewHolder {\n\n    public GenderCellViewHolder(@NonNull View itemView) {\n        super(itemView);\n    }\n\n    @Override\n    public void setData(Object data) {\n        int gender = (int) data;\n        int genderDrawable = gender == TableViewModel.BOY ? R.drawable.ic_male : R.drawable.ic_female;\n\n        cell_image.setImageResource(genderDrawable);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/evrencoskun/tableviewsample/tableview/holder/MoodCellViewHolder.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableviewsample.tableview.holder;\n\nimport android.view.View;\nimport android.widget.ImageView;\n\nimport androidx.annotation.NonNull;\n\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder;\nimport com.evrencoskun.tableviewsample.R;\nimport com.evrencoskun.tableviewsample.tableview.TableViewModel;\n\n/**\n * Created by evrencoskun on 4.02.2018.\n */\n\npublic class MoodCellViewHolder extends AbstractViewHolder {\n    @NonNull\n    public final ImageView cell_image;\n\n    public MoodCellViewHolder(@NonNull View itemView) {\n        super(itemView);\n        cell_image = itemView.findViewById(R.id.cell_image);\n    }\n\n    public void setData(Object data) {\n        int mood = (int) data;\n        int moodDrawable = mood == TableViewModel.HAPPY ? R.drawable.ic_happy : R.drawable.ic_sad;\n\n        cell_image.setImageResource(moodDrawable);\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/evrencoskun/tableviewsample/tableview/holder/RowHeaderViewHolder.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableviewsample.tableview.holder;\n\nimport android.view.View;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\n\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder;\nimport com.evrencoskun.tableviewsample.R;\n\n/**\n * Created by evrencoskun on 23/10/2017.\n */\n\npublic class RowHeaderViewHolder extends AbstractViewHolder {\n    @NonNull\n    public final TextView row_header_textview;\n\n    public RowHeaderViewHolder(@NonNull View itemView) {\n        super(itemView);\n        row_header_textview = itemView.findViewById(R.id.row_header_textview);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/evrencoskun/tableviewsample/tableview/model/Cell.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableviewsample.tableview.model;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.evrencoskun.tableview.filter.IFilterableModel;\nimport com.evrencoskun.tableview.sort.ISortableModel;\n\n/**\n * Created by evrencoskun on 11/06/2017.\n */\n\npublic class Cell implements ISortableModel, IFilterableModel {\n    @NonNull\n    private final String mId;\n    @Nullable\n    private final Object mData;\n    @NonNull\n    private final String mFilterKeyword;\n\n    public Cell(@NonNull String id, @Nullable Object data) {\n        this.mId = id;\n        this.mData = data;\n        this.mFilterKeyword = String.valueOf(data);\n    }\n\n    /**\n     * This is necessary for sorting process.\n     * See ISortableModel\n     */\n    @NonNull\n    @Override\n    public String getId() {\n        return mId;\n    }\n\n    /**\n     * This is necessary for sorting process.\n     * See ISortableModel\n     */\n    @Nullable\n    @Override\n    public Object getContent() {\n        return mData;\n    }\n\n    @Nullable\n    public Object getData() {\n        return mData;\n    }\n\n    @NonNull\n    @Override\n    public String getFilterableKeyword() {\n        return mFilterKeyword;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/evrencoskun/tableviewsample/tableview/model/ColumnHeader.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableviewsample.tableview.model;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\n/**\n * Created by evrencoskun on 11/06/2017.\n */\n\npublic class ColumnHeader extends Cell {\n    public ColumnHeader(@NonNull String id, @Nullable String data) {\n        super(id, data);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/evrencoskun/tableviewsample/tableview/model/RowHeader.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableviewsample.tableview.model;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\n/**\n * Created by evrencoskun on 11/06/2017.\n */\n\npublic class RowHeader extends Cell {\n    public RowHeader(@NonNull String id, @Nullable String data) {\n        super(id, data);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/evrencoskun/tableviewsample/tableview/popup/ColumnHeaderLongPressPopup.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableviewsample.tableview.popup;\n\nimport android.content.Context;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.widget.PopupMenu;\n\nimport androidx.annotation.NonNull;\n\nimport com.evrencoskun.tableview.TableView;\nimport com.evrencoskun.tableview.sort.SortState;\nimport com.evrencoskun.tableviewsample.R;\nimport com.evrencoskun.tableviewsample.tableview.holder.ColumnHeaderViewHolder;\n\n/**\n * Created by evrencoskun on 24.12.2017.\n */\n\npublic class ColumnHeaderLongPressPopup extends PopupMenu implements PopupMenu\n        .OnMenuItemClickListener {\n    // Menu Item constants\n    private static final int ASCENDING = 1;\n    private static final int DESCENDING = 2;\n    private static final int HIDE_ROW = 3;\n    private static final int SHOW_ROW = 4;\n    private static final int SCROLL_ROW = 5;\n\n    @NonNull\n    private final TableView mTableView;\n    private final int mXPosition;\n\n    public ColumnHeaderLongPressPopup(@NonNull ColumnHeaderViewHolder viewHolder, @NonNull TableView tableView) {\n        super(viewHolder.itemView.getContext(), viewHolder.itemView);\n        this.mTableView = tableView;\n        this.mXPosition = viewHolder.getBindingAdapterPosition();\n\n        initialize();\n    }\n\n    private void initialize() {\n        createMenuItem();\n        changeMenuItemVisibility();\n\n        this.setOnMenuItemClickListener(this);\n    }\n\n    private void createMenuItem() {\n        Context context = mTableView.getContext();\n        this.getMenu().add(Menu.NONE, ASCENDING, 0, context.getString(R.string.sort_ascending));\n        this.getMenu().add(Menu.NONE, DESCENDING, 1, context.getString(R.string.sort_descending));\n        this.getMenu().add(Menu.NONE, HIDE_ROW, 2, context.getString(R.string.hiding_row_sample));\n        this.getMenu().add(Menu.NONE, SHOW_ROW, 3, context.getString(R.string.showing_row_sample));\n        this.getMenu().add(Menu.NONE, SCROLL_ROW, 4, context.getString(R.string.scroll_to_row_position));\n        this.getMenu().add(Menu.NONE, SCROLL_ROW, 0, \"change width\");\n        // add new one ...\n\n    }\n\n    private void changeMenuItemVisibility() {\n        // Determine which one shouldn't be visible\n        SortState sortState = mTableView.getSortingStatus(mXPosition);\n        if (sortState == SortState.UNSORTED) {\n            // Show others\n        } else if (sortState == SortState.DESCENDING) {\n            // Hide DESCENDING menu item\n            getMenu().getItem(1).setVisible(false);\n        } else if (sortState == SortState.ASCENDING) {\n            // Hide ASCENDING menu item\n            getMenu().getItem(0).setVisible(false);\n        }\n    }\n\n    @Override\n    public boolean onMenuItemClick(MenuItem menuItem) {\n        // Note: item id is index of menu item..\n\n        switch (menuItem.getItemId()) {\n            case ASCENDING:\n                mTableView.sortColumn(mXPosition, SortState.ASCENDING);\n\n                break;\n            case DESCENDING:\n                mTableView.sortColumn(mXPosition, SortState.DESCENDING);\n                break;\n            case HIDE_ROW:\n                mTableView.hideRow(5);\n                break;\n            case SHOW_ROW:\n                mTableView.showRow(5);\n                break;\n            case SCROLL_ROW:\n                mTableView.scrollToRowPosition(5);\n                break;\n        }\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/evrencoskun/tableviewsample/tableview/popup/RowHeaderLongPressPopup.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableviewsample.tableview.popup;\n\nimport android.content.Context;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.widget.PopupMenu;\n\nimport androidx.annotation.NonNull;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.evrencoskun.tableview.TableView;\nimport com.evrencoskun.tableviewsample.R;\n\n/**\n * Created by evrencoskun on 21.01.2018.\n */\n\npublic class RowHeaderLongPressPopup extends PopupMenu implements PopupMenu\n        .OnMenuItemClickListener {\n\n    // Menu Item constants\n    private static final int SCROLL_COLUMN = 1;\n    private static final int SHOWHIDE_COLUMN = 2;\n    private static final int REMOVE_ROW = 3;\n\n    @NonNull\n    private final TableView mTableView;\n    private final int mRowPosition;\n\n    public RowHeaderLongPressPopup(@NonNull RecyclerView.ViewHolder viewHolder, @NonNull TableView tableView) {\n        super(viewHolder.itemView.getContext(), viewHolder.itemView);\n\n        this.mTableView = tableView;\n        this.mRowPosition = viewHolder.getBindingAdapterPosition();\n\n        initialize();\n    }\n\n    private void initialize() {\n        createMenuItem();\n\n        this.setOnMenuItemClickListener(this);\n    }\n\n    private void createMenuItem() {\n        Context context = mTableView.getContext();\n        this.getMenu().add(Menu.NONE, SCROLL_COLUMN, 0, context.getString(R.string\n                .scroll_to_column_position));\n        this.getMenu().add(Menu.NONE, SHOWHIDE_COLUMN, 1, context.getString(R.string\n                .show_hide_the_column));\n        this.getMenu().add(Menu.NONE, REMOVE_ROW, 2, \"Remove \" + mRowPosition + \" position\");\n        // add new one ...\n\n    }\n\n    @Override\n    public boolean onMenuItemClick(MenuItem menuItem) {\n        // Note: item id is index of menu item..\n\n        switch (menuItem.getItemId()) {\n            case SCROLL_COLUMN:\n                mTableView.scrollToColumnPosition(15);\n                break;\n            case SHOWHIDE_COLUMN:\n                int column = 1;\n                if (mTableView.isColumnVisible(column)) {\n                    mTableView.hideColumn(column);\n                } else {\n                    mTableView.showColumn(column);\n                }\n\n                break;\n            case REMOVE_ROW:\n                mTableView.getAdapter().removeRow(mRowPosition);\n                break;\n        }\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_down.xml",
    "content": "<!--\n ~ MIT License\n ~\n ~ Copyright (c) 2021 Evren Coşkun\n ~\n ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n ~ of this software and associated documentation files (the \"Software\"), to deal\n ~ in the Software without restriction, including without limitation the rights\n ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n ~ copies of the Software, and to permit persons to whom the Software is\n ~ furnished to do so, subject to the following conditions:\n ~\n ~ The above copyright notice and this permission notice shall be included in all\n ~ copies or substantial portions of the Software.\n ~\n ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n ~ SOFTWARE.\n  -->\n<vector android:height=\"24dp\" android:viewportHeight=\"512.0\"\n    android:viewportWidth=\"512.0\" android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#FF000000\" android:pathData=\"M396.6,160l19.4,20.7l-160,171.3l-160,-171.3l19.3,-20.7l140.7,150.5z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_female.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:width=\"24dp\"\n        android:height=\"24dp\"\n        android:viewportWidth=\"24.0\"\n        android:viewportHeight=\"24.0\">\n    <path\n        android:fillColor=\"#FFAA0099\"\n        android:pathData=\"M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_happy.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:width=\"24dp\"\n        android:height=\"24dp\"\n        android:viewportWidth=\"24.0\"\n        android:viewportHeight=\"24.0\">\n    <path\n        android:fillColor=\"#FF00FF00\"\n        android:pathData=\"M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM15.5,11c0.83,0 1.5,-0.67 1.5,-1.5S16.33,8 15.5,8 14,8.67 14,9.5s0.67,1.5 1.5,1.5zM8.5,11c0.83,0 1.5,-0.67 1.5,-1.5S9.33,8 8.5,8 7,8.67 7,9.5 7.67,11 8.5,11zM12,17.5c2.33,0 4.31,-1.46 5.11,-3.5L6.89,14c0.8,2.04 2.78,3.5 5.11,3.5z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_male.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:width=\"24dp\"\n        android:height=\"24dp\"\n        android:viewportWidth=\"24.0\"\n        android:viewportHeight=\"24.0\">\n    <path\n        android:fillColor=\"#FF5511FF\"\n        android:pathData=\"M4,12l1.41,1.41L11,7.83V20h2V7.83l5.58,5.59L20,12l-8,-8 -8,8z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_next.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:width=\"24dp\"\n        android:height=\"24dp\"\n        android:viewportWidth=\"24.0\"\n        android:viewportHeight=\"24.0\">\n    <path\n        android:fillColor=\"#FF000000\"\n        android:pathData=\"M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_previous.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:width=\"24dp\"\n        android:height=\"24dp\"\n        android:viewportWidth=\"24.0\"\n        android:viewportHeight=\"24.0\">\n    <path\n        android:fillColor=\"#FF000000\"\n        android:pathData=\"M15.41,7.41L14,6l-6,6 6,6 1.41,-1.41L10.83,12z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_sad.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:width=\"24dp\"\n        android:height=\"24dp\"\n        android:viewportWidth=\"24.0\"\n        android:viewportHeight=\"24.0\">\n    <path\n        android:fillColor=\"#FFFF0000\"\n        android:pathData=\"M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM15.5,11c0.83,0 1.5,-0.67 1.5,-1.5S16.33,8 15.5,8 14,8.67 14,9.5s0.67,1.5 1.5,1.5zM8.5,11c0.83,0 1.5,-0.67 1.5,-1.5S9.33,8 8.5,8 7,8.67 7,9.5 7.67,11 8.5,11zM12,14c-2.33,0 -4.31,1.46 -5.11,3.5h10.22c-0.8,-2.04 -2.78,-3.5 -5.11,-3.5z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_up.xml",
    "content": "<!--\n ~ MIT License\n ~\n ~ Copyright (c) 2021 Evren Coşkun\n ~\n ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n ~ of this software and associated documentation files (the \"Software\"), to deal\n ~ in the Software without restriction, including without limitation the rights\n ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n ~ copies of the Software, and to permit persons to whom the Software is\n ~ furnished to do so, subject to the following conditions:\n ~\n ~ The above copyright notice and this permission notice shall be included in all\n ~ copies or substantial portions of the Software.\n ~\n ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n ~ SOFTWARE.\n  -->\n<vector android:height=\"24dp\" android:viewportHeight=\"512.0\"\n    android:viewportWidth=\"512.0\" android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#FF000000\" android:pathData=\"M396.6,352l19.4,-20.7l-160,-171.3l-160,171.3l19.3,20.7l140.7,-150.5z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.fragment.app.FragmentContainerView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/fragment_main\"\n    android:name=\"com.evrencoskun.tableviewsample.MainFragment\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:layout=\"@layout/fragment_main\" />\n\n"
  },
  {
    "path": "app/src/main/res/layout/fragment_main.xml",
    "content": "<!--\n ~ MIT License\n ~\n ~ Copyright (c) 2021 Evren Coşkun\n ~\n ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n ~ of this software and associated documentation files (the \"Software\"), to deal\n ~ in the Software without restriction, including without limitation the rights\n ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n ~ copies of the Software, and to permit persons to whom the Software is\n ~ furnished to do so, subject to the following conditions:\n ~\n ~ The above copyright notice and this permission notice shall be included in all\n ~ copies or substantial portions of the Software.\n ~\n ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n ~ SOFTWARE.\n  -->\n<RelativeLayout\n    android:id=\"@+id/fragment_container\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@color/bg_line\"\n    android:focusableInTouchMode=\"true\">\n\n\n    <LinearLayout\n        android:id=\"@+id/table_test_container\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n        <LinearLayout\n            android:id=\"@+id/search_field\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"center_vertical\"\n            android:orientation=\"horizontal\"\n            android:weightSum=\"100\">\n\n            <EditText\n                android:id=\"@+id/query_string\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"40\"\n                android:inputType=\"textNoSuggestions\"/>\n\n            <Spinner\n                android:id=\"@+id/mood_spinner\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"30\"\n                android:background=\"@android:color/transparent\"\n                android:entries=\"@array/moods\"/>\n\n            <Spinner\n                android:id=\"@+id/gender_spinner\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"30\"\n                android:background=\"@android:color/transparent\"\n                android:entries=\"@array/gender\"/>\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"center_vertical\"\n            android:orientation=\"horizontal\"\n            android:weightSum=\"100\">\n\n            <ImageButton\n                android:id=\"@+id/previous_button\"\n                android:layout_width=\"48dp\"\n                android:layout_height=\"48dp\"\n                app:srcCompat=\"@drawable/ic_previous\"/>\n\n            <EditText\n                android:id=\"@+id/page_number_text\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"20\"\n                android:inputType=\"number\"/>\n\n            <ImageButton\n                android:id=\"@+id/next_button\"\n                android:layout_width=\"48dp\"\n                android:layout_height=\"48dp\"\n                app:srcCompat=\"@drawable/ic_next\"/>\n\n            <TextView\n                android:id=\"@+id/table_details\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"50\"/>\n\n            <Spinner\n                android:id=\"@+id/items_per_page_spinner\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"30\"\n                android:background=\"@android:color/transparent\"\n                android:entries=\"@array/items_per_page\"/>\n        </LinearLayout>\n    </LinearLayout>\n\n    <com.evrencoskun.tableview.TableView\n        android:id=\"@+id/tableview\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_below=\"@+id/table_test_container\"\n        app:allow_click_inside_cell=\"true\"\n        app:allow_click_inside_column_header=\"true\"\n        app:allow_click_inside_row_header=\"true\">\n\n    </com.evrencoskun.tableview.TableView>\n</RelativeLayout>\n\n"
  },
  {
    "path": "app/src/main/res/layout/table_view_cell_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n ~ MIT License\n ~\n ~ Copyright (c) 2021 Evren Coşkun\n ~\n ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n ~ of this software and associated documentation files (the \"Software\"), to deal\n ~ in the Software without restriction, including without limitation the rights\n ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n ~ copies of the Software, and to permit persons to whom the Software is\n ~ furnished to do so, subject to the following conditions:\n ~\n ~ The above copyright notice and this permission notice shall be included in all\n ~ copies or substantial portions of the Software.\n ~\n ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n ~ SOFTWARE.\n  -->\n<LinearLayout android:id=\"@+id/cell_container\"\n              xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              xmlns:tools=\"http://schemas.android.com/tools\"\n              android:layout_width=\"wrap_content\"\n              android:layout_height=\"@dimen/cell_height\"\n              android:background=\"@color/cell_background_color\"\n              android:gravity=\"center\"\n              android:orientation=\"vertical\">\n\n\n    <TextView\n        android:id=\"@+id/cell_data\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"center_vertical\"\n        android:layout_marginEnd=\"10dp\"\n        android:layout_marginStart=\"10dp\"\n        android:gravity=\"center\"\n        android:maxLines=\"1\"\n        android:textColor=\"@color/table_view_default_text_color\"\n        android:textSize=\"@dimen/text_size\"\n        android:visibility=\"visible\"\n        tools:text=\"Cell Data\"/>\n\n</LinearLayout>\n\n"
  },
  {
    "path": "app/src/main/res/layout/table_view_column_header_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n ~ MIT License\n ~\n ~ Copyright (c) 2021 Evren Coşkun\n ~\n ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n ~ of this software and associated documentation files (the \"Software\"), to deal\n ~ in the Software without restriction, including without limitation the rights\n ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n ~ copies of the Software, and to permit persons to whom the Software is\n ~ furnished to do so, subject to the following conditions:\n ~\n ~ The above copyright notice and this permission notice shall be included in all\n ~ copies or substantial portions of the Software.\n ~\n ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n ~ SOFTWARE.\n  -->\n<LinearLayout\n    android:id=\"@+id/column_header_container\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"@dimen/cell_height\"\n    android:background=\"@color/cell_background_color\"\n    android:orientation=\"vertical\">\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"horizontal\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_gravity=\"center\"\n            android:layout_marginEnd=\"10dp\"\n            android:layout_marginStart=\"10dp\"\n            android:orientation=\"horizontal\">\n\n            <TextView\n                android:id=\"@+id/column_header_textView\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:layout_gravity=\"center\"\n                android:layout_weight=\"4\"\n                android:gravity=\"center\"\n                android:textColor=\"@color/table_view_default_text_color\"\n                android:textSize=\"@dimen/text_size\"\n                tools:text=\"Header Data\"/>\n\n            <ImageButton\n                android:id=\"@+id/column_header_sortButton\"\n                android:layout_width=\"15dp\"\n                android:layout_height=\"15dp\"\n                android:layout_gravity=\"end|center\"\n                android:layout_marginLeft=\"4dp\"\n                android:background=\"@android:color/transparent\"\n                android:paddingRight=\"-5dp\"\n                android:scaleType=\"fitXY\"\n                android:visibility=\"gone\"\n                app:srcCompat=\"@drawable/ic_down\"/>\n        </LinearLayout>\n\n        <View\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"1dp\"\n            android:layout_gravity=\"bottom\"\n            android:background=\"@color/header_line_color\"/>\n    </FrameLayout>\n</LinearLayout>\n\n"
  },
  {
    "path": "app/src/main/res/layout/table_view_corner_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n ~ MIT License\n ~\n ~ Copyright (c) 2021 Evren Coşkun\n ~\n ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n ~ of this software and associated documentation files (the \"Software\"), to deal\n ~ in the Software without restriction, including without limitation the rights\n ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n ~ copies of the Software, and to permit persons to whom the Software is\n ~ furnished to do so, subject to the following conditions:\n ~\n ~ The above copyright notice and this permission notice shall be included in all\n ~ copies or substantial portions of the Software.\n ~\n ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n ~ SOFTWARE.\n  -->\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n                android:layout_width=\"@dimen/row_header_width\"\n                android:layout_height=\"@dimen/cell_height\"\n                android:background=\"@color/cell_background_color\">\n\n    <TextView\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_centerVertical=\"true\"\n        android:text=\"Corner\"\n        android:textColor=\"@color/table_view_default_text_color\"\n        android:textSize=\"@dimen/text_size\"/>\n\n    <View\n        android:layout_width=\"1dp\"\n        android:layout_height=\"match_parent\"\n        android:layout_alignParentRight=\"true\"\n        android:background=\"@color/header_line_color\"/>\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1dp\"\n        android:layout_alignParentBottom=\"true\"\n        android:background=\"@color/header_line_color\"/>\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/table_view_image_cell_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n ~ MIT License\n ~\n ~ Copyright (c) 2021 Evren Coşkun\n ~\n ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n ~ of this software and associated documentation files (the \"Software\"), to deal\n ~ in the Software without restriction, including without limitation the rights\n ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n ~ copies of the Software, and to permit persons to whom the Software is\n ~ furnished to do so, subject to the following conditions:\n ~\n ~ The above copyright notice and this permission notice shall be included in all\n ~ copies or substantial portions of the Software.\n ~\n ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n ~ SOFTWARE.\n  -->\n<LinearLayout android:id=\"@+id/cell_container\"\n              xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n              android:layout_width=\"wrap_content\"\n              android:layout_height=\"@dimen/cell_height\"\n              android:background=\"@color/cell_background_color\"\n              android:gravity=\"center\"\n              android:orientation=\"vertical\">\n\n    <ImageView\n        android:id=\"@+id/cell_image\"\n        android:layout_width=\"32dp\"\n        android:layout_height=\"32dp\"\n        android:contentDescription=\"@string/app_name\"\n        app:srcCompat=\"@drawable/ic_happy\"/>\n\n</LinearLayout>\n\n"
  },
  {
    "path": "app/src/main/res/layout/table_view_row_header_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n ~ MIT License\n ~\n ~ Copyright (c) 2021 Evren Coşkun\n ~\n ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n ~ of this software and associated documentation files (the \"Software\"), to deal\n ~ in the Software without restriction, including without limitation the rights\n ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n ~ copies of the Software, and to permit persons to whom the Software is\n ~ furnished to do so, subject to the following conditions:\n ~\n ~ The above copyright notice and this permission notice shall be included in all\n ~ copies or substantial portions of the Software.\n ~\n ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n ~ SOFTWARE.\n  -->\n<RelativeLayout android:id=\"@+id/root\"\n                xmlns:android=\"http://schemas.android.com/apk/res/android\"\n                xmlns:tools=\"http://schemas.android.com/tools\"\n                android:background=\"@color/cell_background_color\"\n                android:layout_width=\"@dimen/row_header_width\"\n                android:layout_height=\"@dimen/cell_height\">\n\n    <LinearLayout\n        android:id=\"@+id/row_header_container\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/row_header_textview\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:ellipsize=\"end\"\n            android:gravity=\"center\"\n            android:maxLines=\"1\"\n            android:textColor=\"@color/table_view_default_text_color\"\n            android:textSize=\"@dimen/text_size\"\n            tools:text=\"Row Data\"/>\n\n    </LinearLayout>\n\n    <View\n        android:layout_width=\"1dp\"\n        android:layout_height=\"match_parent\"\n        android:layout_alignParentRight=\"true\"\n        android:background=\"@color/header_line_color\"/>\n</RelativeLayout>"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n ~ MIT License\n ~\n ~ Copyright (c) 2021 Evren Coşkun\n ~\n ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n ~ of this software and associated documentation files (the \"Software\"), to deal\n ~ in the Software without restriction, including without limitation the rights\n ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n ~ copies of the Software, and to permit persons to whom the Software is\n ~ furnished to do so, subject to the following conditions:\n ~\n ~ The above copyright notice and this permission notice shall be included in all\n ~ copies or substantial portions of the Software.\n ~\n ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n ~ SOFTWARE.\n  -->\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"colorPrimaryDark\">#303F9F</color>\n    <color name=\"colorAccent\">#FF4081</color>\n    <color name=\"bg_line\">#E7E7E7</color>\n\n    <color name=\"cell_background_color\">#ffffff</color>\n    <color name=\"header_line_color\">@android:color/holo_red_light</color>\n\n    <color name=\"table_view_default_text_color\">#0a0a0a</color>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/dimens.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n ~ MIT License\n ~\n ~ Copyright (c) 2021 Evren Coşkun\n ~\n ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n ~ of this software and associated documentation files (the \"Software\"), to deal\n ~ in the Software without restriction, including without limitation the rights\n ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n ~ copies of the Software, and to permit persons to whom the Software is\n ~ furnished to do so, subject to the following conditions:\n ~\n ~ The above copyright notice and this permission notice shall be included in all\n ~ copies or substantial portions of the Software.\n ~\n ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n ~ SOFTWARE.\n  -->\n<resources>\n    <dimen name=\"cell_height\">40dp</dimen>\n    <dimen name=\"row_header_width\">55dp</dimen>\n    <dimen name=\"text_size\">12sp</dimen>\n\n    <!-- Overriding the default values of the tableView -->\n    <dimen name=\"default_row_header_width\">55dp</dimen>\n    <dimen name=\"default_column_header_height\">40dp</dimen>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n ~ MIT License\n ~\n ~ Copyright (c) 2021 Evren Coşkun\n ~\n ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n ~ of this software and associated documentation files (the \"Software\"), to deal\n ~ in the Software without restriction, including without limitation the rights\n ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n ~ copies of the Software, and to permit persons to whom the Software is\n ~ furnished to do so, subject to the following conditions:\n ~\n ~ The above copyright notice and this permission notice shall be included in all\n ~ copies or substantial portions of the Software.\n ~\n ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n ~ SOFTWARE.\n  -->\n<resources>\n    <string name=\"app_name\">TableViewSample</string>\n\n    <!-- TODO: Remove or change this placeholder text -->\n    <string name=\"sort_ascending\">Sort Ascending</string>\n    <string name=\"sort_descending\">Sort Descending</string>\n    <string name=\"hiding_row_sample\">Hiding 3. Row Sample</string>\n    <string name=\"showing_row_sample\">Showing 3. Row Sample</string>\n    <string name=\"scroll_to_column_position\">Scroll to 15. column position</string>\n    <string name=\"scroll_to_row_position\">Scroll to 5. row position</string>\n    <string name=\"show_hide_the_column\">Showing / Hiding 1. column</string>\n    <string name=\"table_pagination_details\">Page %s, showing items %s - %s.</string>\n\n    <string-array name=\"moods\">\n        <item />\n        <item>Happy</item>\n        <item>Sad</item>\n    </string-array>\n\n    <string-array name=\"gender\">\n        <item />\n        <item>Male</item>\n        <item>Female</item>\n    </string-array>\n\n    <string-array name=\"items_per_page\">\n        <item>10</item>\n        <item>20</item>\n        <item>25</item>\n        <item>50</item>\n        <item>All</item>\n    </string-array>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n ~ MIT License\n ~\n ~ Copyright (c) 2021 Evren Coşkun\n ~\n ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n ~ of this software and associated documentation files (the \"Software\"), to deal\n ~ in the Software without restriction, including without limitation the rights\n ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n ~ copies of the Software, and to permit persons to whom the Software is\n ~ furnished to do so, subject to the following conditions:\n ~\n ~ The above copyright notice and this permission notice shall be included in all\n ~ copies or substantial portions of the Software.\n ~\n ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n ~ SOFTWARE.\n  -->\n<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.NoActionBar\">\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "build.gradle",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    ext.android_gradle_plugin_version = '4.2.1'\n    ext.androidx_annotation_version = '1.2.0'\n    ext.androidx_appcompat_version = '1.3.0'\n    ext.androidx_core_version = '1.5.0'\n    ext.androidx_fragment_version = '1.3.5'\n    ext.androidx_recyclerview_version = '1.2.1'\n    ext.androidx_test_version = '1.3.0'\n    ext.androidx_test_espresso_version = '3.3.0'\n    ext.androidx_test_ext_version = '1.1.2'\n    ext.compile_sdk_version = 29\n    ext.java_version = '1.8'\n    ext.junit_version = '4.13.2'\n    ext.min_sdk_version = 14\n    ext.target_sdk_version = 29\n\n    repositories {\n        jcenter()\n        google()\n    }\n\n    dependencies {\n        classpath \"com.android.tools.build:gradle:$android_gradle_plugin_version\"\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        jcenter()\n        google()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n\nsubprojects {\n    if (project.getGradle().startParameter.taskNames.any{it.contains('bintrayUpload')} && project.name in ['tableview']) {\n        println project.name\n        apply plugin: 'maven'\n\n        gradle.taskGraph.whenReady { taskGraph ->\n            def pomTask = taskGraph.getAllTasks().find {\n                it.path == \":$project.name:generatePomFileForReleasePublication\"\n            }\n            if (pomTask == null) println 'pomTask null'\n            if (pomTask == null) return\n            pomTask.doLast {\n                println 'Updating pom-file(s) with License info'\n                pomTask.outputs.files\n                        .filter { File file ->\n                            file.path.contains(\"publications\") && file.name.matches(\"^pom-.+\\\\.xml\\$\")\n                        }\n                        .forEach { File file -> addLicense(file) }\n            }\n        }\n    }\n}\n\nstatic void addLicense(File pom) {\n    def licenseNode = new Node(null, \"license\")\n    licenseNode.append(new Node(null, \"name\", \"MIT\"))\n    licenseNode.append(new Node(null, \"url\", \"https://github.com/evrencoskun/TableView/blob/master/LICENSE\"))\n    def licensesNode = new Node(null, \"licenses\")\n    licensesNode.append(licenseNode)\n\n    def xml = new XmlParser().parse(pom)\n    xml.append(licensesNode)\n\n    def writer = new PrintWriter(new FileWriter(pom))\n    def printer = new XmlNodePrinter(writer)\n    printer.preserveWhitespace = true\n    printer.print(xml)\n    writer.close()\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#\n# MIT License\n#\n# Copyright (c) 2021 Evren Coşkun\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in all\n# copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n# SOFTWARE.\n#\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-6.8-all.zip\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx1536m\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n\nandroid.useAndroidX=true"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env sh\n\n#\n# Copyright 2015 the original author or authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif [ \"$cygwin\" = \"true\" -o \"$msys\" = \"true\" ] ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=`expr $i + 1`\n    done\n    case $i in\n        0) set -- ;;\n        1) set -- \"$args0\" ;;\n        2) set -- \"$args0\" \"$args1\" ;;\n        3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=`save \"$@\"`\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@rem\n@rem Copyright 2015 the original author or authors.\n@rem\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\n@rem you may not use this file except in compliance with the License.\n@rem You may obtain a copy of the License at\n@rem\n@rem      https://www.apache.org/licenses/LICENSE-2.0\n@rem\n@rem Unless required by applicable law or agreed to in writing, software\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@rem See the License for the specific language governing permissions and\n@rem limitations under the License.\n@rem\n\n@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto execute\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto execute\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %*\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "settings.gradle",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\ninclude ':app', ':tableview'\n"
  },
  {
    "path": "tableview/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "tableview/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion compile_sdk_version\n\n    defaultConfig {\n        minSdkVersion min_sdk_version\n        targetSdkVersion target_sdk_version\n        versionCode 1\n        versionName '0.8.9.4'\n        testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n        debug {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n            testCoverageEnabled true\n        }\n    }\n\n    compileOptions {\n        sourceCompatibility = java_version\n        targetCompatibility = java_version\n    }\n\n    buildFeatures {\n        buildConfig = false\n    }\n\n    lintOptions {\n        abortOnError false\n    }\n\n    tasks.withType(Javadoc) {\n        options.addStringOption('Xdoclint:none', '-quiet')\n        options.addStringOption('encoding', 'UTF-8')\n        options.addStringOption('charSet', 'UTF-8')\n    }\n}\n\ndependencies {\n    implementation \"androidx.annotation:annotation:$androidx_annotation_version\"\n    implementation \"androidx.recyclerview:recyclerview:$androidx_recyclerview_version\"\n\n    testImplementation \"junit:junit:$junit_version\"\n\n    androidTestImplementation \"androidx.appcompat:appcompat:$androidx_appcompat_version\"\n    androidTestImplementation \"androidx.test:rules:$androidx_test_version\"\n    androidTestImplementation \"androidx.test:runner:$androidx_test_version\"\n    androidTestImplementation \"androidx.test.espresso:espresso-core:$androidx_test_espresso_version\"\n    androidTestImplementation \"androidx.test.espresso:espresso-contrib:$androidx_test_espresso_version\"\n    androidTestImplementation \"androidx.test.ext:junit:$androidx_test_ext_version\"\n    androidTestImplementation \"junit:junit:$junit_version\"\n}\n\n// Configure the publishing\napply plugin: 'maven-publish'\n\ntask androidJavadocs(type: Javadoc) {\n    source = android.sourceSets.main.java.srcDirs\n    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))\n    android.libraryVariants.all { variant ->\n        if (variant.name == 'release') {\n            owner.classpath += variant.javaCompileProvider.get().classpath\n        }\n    }\n    exclude '**/R.html', '**/R.*.html', '**/index.html'\n}\n\ntask androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {\n    archiveClassifier.set('javadoc')\n    from androidJavadocs.destinationDir\n}\n\ntask androidSourcesJar(type: Jar) {\n    archiveClassifier.set('sources')\n    from android.sourceSets.main.java.srcDirs\n}\n\nafterEvaluate {\n    publishing {\n        publications {\n            release(MavenPublication) {\n                from components.release\n\n                groupId = 'com.evrencoskun.library'\n                artifactId = 'tableview'\n                version = android.defaultConfig.versionName\n\n                artifact androidJavadocsJar\n                artifact androidSourcesJar\n\n                pom {\n                    name = 'TableView'\n                    description = 'TableView is a powerful Android library for displaying complex data structures and rendering tabular data composed of rows, columns and cells.'\n                    url = 'https://github.com/evrencoskun/TableView'\n                }\n            }\n        }\n\n        repositories {\n            maven {\n                url = 'https://api.bintray.com/content/evrencoskun/artifact-sandbox/'\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tableview/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /Users/evrencoskun/Library/Android/sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "tableview/src/androidTest/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest package=\"com.evrencoskun.tableview.test\"\n          xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <application>\n        <activity android:name=\".TestActivity\">\n        </activity>\n    </application>\n\n</manifest>"
  },
  {
    "path": "tableview/src/androidTest/java/com/evrencoskun/tableview/test/CornerLayoutTest.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Andrew Beck\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.test;\n\nimport static androidx.test.espresso.Espresso.onView;\nimport static androidx.test.espresso.assertion.PositionAssertions.isCompletelyAbove;\nimport static androidx.test.espresso.assertion.PositionAssertions.isCompletelyBelow;\nimport static androidx.test.espresso.assertion.PositionAssertions.isCompletelyLeftOf;\nimport static androidx.test.espresso.assertion.PositionAssertions.isCompletelyRightOf;\nimport static androidx.test.espresso.assertion.ViewAssertions.matches;\nimport static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;\nimport static androidx.test.espresso.matcher.ViewMatchers.withId;\nimport static androidx.test.espresso.matcher.ViewMatchers.withParent;\nimport static androidx.test.espresso.matcher.ViewMatchers.withParentIndex;\nimport static androidx.test.espresso.matcher.ViewMatchers.withText;\nimport static org.hamcrest.Matchers.allOf;\n\nimport android.widget.RelativeLayout;\n\nimport androidx.test.espresso.matcher.ViewMatchers;\nimport androidx.test.ext.junit.rules.ActivityScenarioRule;\nimport androidx.test.ext.junit.runners.AndroidJUnit4;\n\nimport com.evrencoskun.tableview.ITableView;\nimport com.evrencoskun.tableview.TableView;\nimport com.evrencoskun.tableview.test.adapters.CornerTestAdapter;\nimport com.evrencoskun.tableview.test.data.SimpleData;\nimport com.evrencoskun.tableview.test.matchers.ViewWidthMatcher;\n\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\n@RunWith(AndroidJUnit4.class)\npublic class CornerLayoutTest {\n\n    @Rule\n    public ActivityScenarioRule<TestActivity> mActivityTestRule =\n            new ActivityScenarioRule<>(TestActivity.class);\n\n    @Test\n    public void testDefaultCorner() {\n        mActivityTestRule.getScenario()\n                .onActivity(activity -> {\n                    activity.setContentView(R.layout.corner_default);\n\n                    TableView tableView = activity.findViewById(R.id.tableview);\n\n                    CornerTestAdapter cornerTestAdapter = new CornerTestAdapter();\n\n                    tableView.setAdapter(cornerTestAdapter);\n\n                    SimpleData simpleData = new SimpleData(5);\n\n                    cornerTestAdapter.setAllItems(\n                            simpleData.getColumnHeaders(), simpleData.getRowHeaders(), simpleData.getCells());\n                });\n\n        // Check that the corner view is created and visible\n        // The Corner view uses cell_layout which has RelativeLayout as top item\n        onView(withId(R.id.corner_view))\n                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));\n\n        // Check that it is the expected corner view by checking the text\n        // The first child of the RelativeLayout is a textView (index starts at zero)\n        onView(allOf(withParent(withId(R.id.corner_view)), withParentIndex(0)))\n                .check(matches(withText(\"Corner\")));\n\n        // Check that Corner to is to the right of the column headers\n        onView(withId(R.id.corner_view)).check(isCompletelyLeftOf(withId(R.id.ColumnHeaderRecyclerView)));\n\n        // Check that Corner to is to the above of the row headers\n        onView(withId(R.id.corner_view)).check(isCompletelyAbove(withId(R.id.RowHeaderRecyclerView)));\n    }\n\n    @Test\n    public void testTopLeftCorner() {\n        mActivityTestRule.getScenario()\n                .onActivity(activity -> {\n                    activity.setContentView(R.layout.corner_top_left);\n\n                    TableView tableView = activity.findViewById(R.id.tableview);\n\n                    CornerTestAdapter cornerTestAdapter = new CornerTestAdapter();\n\n                    tableView.setAdapter(cornerTestAdapter);\n\n                    SimpleData simpleData = new SimpleData(5);\n\n                    cornerTestAdapter.setAllItems(\n                            simpleData.getColumnHeaders(), simpleData.getRowHeaders(), simpleData.getCells());\n                });\n\n        // Check that the corner view is created and visible\n        // The Corner view uses cell_layout which has RelativeLayout as top item\n        onView(withId(R.id.corner_view))\n                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));\n\n        // Check that it is the expected corner view by checking the text\n        // The first child of the RelativeLayout is a textView (index starts at zero)\n        onView(allOf(withParent(withId(R.id.corner_view)), withParentIndex(0)))\n                .check(matches(withText(\"Corner\")));\n\n        // Check that Corner to is to the right of the column headers\n        onView(withId(R.id.corner_view)).check(isCompletelyLeftOf(withId(R.id.ColumnHeaderRecyclerView)));\n\n        // Check that Corner to is to the above of the row headers\n        onView(withId(R.id.corner_view)).check(isCompletelyAbove(withId(R.id.RowHeaderRecyclerView)));\n    }\n\n    @Test\n    public void testBottomLeftCorner() {\n        mActivityTestRule.getScenario()\n                .onActivity(activity -> {\n                    activity.setContentView(R.layout.corner_bottom_left);\n\n                    TableView tableView = activity.findViewById(R.id.tableview);\n\n                    CornerTestAdapter cornerTestAdapter = new CornerTestAdapter();\n\n                    tableView.setAdapter(cornerTestAdapter);\n\n                    SimpleData simpleData = new SimpleData(5);\n\n                    cornerTestAdapter.setAllItems(\n                            simpleData.getColumnHeaders(), simpleData.getRowHeaders(), simpleData.getCells());\n                });\n\n        // Check that the corner view is created and visible\n        // The Corner view uses cell_layout which has RelativeLayout as top item\n        onView(withId(R.id.corner_view))\n                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));\n\n        // Check that it is the expected corner view by checking the text\n        // The first child of the RelativeLayout is a textView (index starts at zero)\n        onView(allOf(withParent(withId(R.id.corner_view)), withParentIndex(0)))\n                .check(matches(withText(\"Corner\")));\n\n        // Check that Corner to is to the right of the column headers\n        onView(withId(R.id.corner_view)).check(isCompletelyLeftOf(withId(R.id.ColumnHeaderRecyclerView)));\n\n        // Check that Corner to is to the above of the row headers\n        onView(withId(R.id.corner_view)).check(isCompletelyBelow(withId(R.id.RowHeaderRecyclerView)));\n    }\n\n    @Test\n    public void testTopRightCorner() {\n        mActivityTestRule.getScenario()\n                .onActivity(activity -> {\n                    activity.setContentView(R.layout.corner_top_right);\n\n                    TableView tableView = activity.findViewById(R.id.tableview);\n\n                    CornerTestAdapter cornerTestAdapter = new CornerTestAdapter();\n\n                    tableView.setAdapter(cornerTestAdapter);\n\n                    SimpleData simpleData = new SimpleData(5);\n\n                    cornerTestAdapter.setAllItems(\n                            simpleData.getColumnHeaders(), simpleData.getRowHeaders(), simpleData.getCells());\n                });\n\n        // Check that the corner view is created and visible\n        // The Corner view uses cell_layout which has RelativeLayout as top item\n        onView(withId(R.id.corner_view))\n                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));\n\n        // Check that it is the expected corner view by checking the text\n        // The first child of the RelativeLayout is a textView (index starts at zero)\n        onView(allOf(withParent(withId(R.id.corner_view)), withParentIndex(0)))\n                .check(matches(withText(\"Corner\")));\n\n        // Check that Corner to is to the right of the column headers\n        onView(withId(R.id.corner_view)).check(isCompletelyRightOf(withId(R.id.ColumnHeaderRecyclerView)));\n\n        // Check that Corner to is to the above of the row headers\n        onView(withId(R.id.corner_view)).check(isCompletelyAbove(withId(R.id.RowHeaderRecyclerView)));\n    }\n\n    @Test\n    public void testBottomRightCorner() {\n        mActivityTestRule.getScenario()\n                .onActivity(activity -> {\n                    activity.setContentView(R.layout.corner_bottom_right);\n\n                    TableView tableView = activity.findViewById(R.id.tableview);\n\n                    CornerTestAdapter cornerTestAdapter = new CornerTestAdapter();\n\n                    tableView.setAdapter(cornerTestAdapter);\n\n                    SimpleData simpleData = new SimpleData(5);\n\n                    cornerTestAdapter.setAllItems(\n                            simpleData.getColumnHeaders(), simpleData.getRowHeaders(), simpleData.getCells());\n                });\n\n        // Check that the corner view is created and visible\n        // The Corner view uses cell_layout which has RelativeLayout as top item\n        onView(withId(R.id.corner_view))\n                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));\n\n        // Check that it is the expected corner view by checking the text\n        // The first child of the RelativeLayout is a textView (index starts at zero)\n        onView(allOf(withParent(withId(R.id.corner_view)), withParentIndex(0)))\n                .check(matches(withText(\"Corner\")));\n\n        // Check that Corner to is to the right of the column headers\n        onView(withId(R.id.corner_view)).check(isCompletelyRightOf(withId(R.id.ColumnHeaderRecyclerView)));\n\n        // Check that Corner to is to the above of the row headers\n        onView(withId(R.id.corner_view)).check(isCompletelyBelow(withId(R.id.RowHeaderRecyclerView)));\n    }\n\n    @Test\n    public void testCornerConstructor() {\n        mActivityTestRule.getScenario()\n                .onActivity(activity -> {\n                    TableView tableView = new TableView(activity, false);\n\n                    // initialize was false so set properties and call initialize\n                    tableView.setCornerViewLocation(ITableView.CornerViewLocation.BOTTOM_LEFT);\n                    tableView.initialize();\n\n                    RelativeLayout rl = new RelativeLayout(activity);\n                    rl.addView(tableView);\n\n                    CornerTestAdapter cornerTestAdapter = new CornerTestAdapter();\n\n                    tableView.setAdapter(cornerTestAdapter);\n\n                    SimpleData simpleData = new SimpleData(5);\n\n                    cornerTestAdapter.setAllItems(\n                            simpleData.getColumnHeaders(), simpleData.getRowHeaders(), simpleData.getCells());\n\n                    activity.setContentView(rl);\n                });\n\n        // Check that the corner view is created and visible\n        // The Corner view uses cell_layout which has RelativeLayout as top item\n        onView(withId(R.id.corner_view))\n                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));\n\n        // Check that it is the expected corner view by checking the text\n        // The first child of the RelativeLayout is a textView (index starts at zero)\n        onView(allOf(withParent(withId(R.id.corner_view)), withParentIndex(0)))\n                .check(matches(withText(\"Corner\")));\n\n        // Check that Corner to is to the right of the column headers\n        onView(withId(R.id.corner_view)).check(isCompletelyLeftOf(withId(R.id.ColumnHeaderRecyclerView)));\n\n        // Check that Corner to is to the above of the row headers\n        onView(withId(R.id.corner_view)).check(isCompletelyBelow(withId(R.id.RowHeaderRecyclerView)));\n    }\n\n    @Test\n    public void testSetRowHeaderWidthLeft() {\n        mActivityTestRule.getScenario()\n                .onActivity(activity -> {\n                    activity.setContentView(R.layout.corner_top_left);\n\n                    TableView tableView = activity.findViewById(R.id.tableview);\n\n                    CornerTestAdapter cornerTestAdapter = new CornerTestAdapter();\n\n                    tableView.setAdapter(cornerTestAdapter);\n\n                    SimpleData simpleData = new SimpleData(5);\n\n                    cornerTestAdapter.setAllItems(\n                            simpleData.getColumnHeaders(), simpleData.getRowHeaders(), simpleData.getCells());\n\n                    // Set a new width on row header\n                    tableView.setRowHeaderWidth(200);\n                });\n\n        // Check that the corner view is created and visible\n        // The Corner view uses cell_layout which has RelativeLayout as top item\n        onView(withId(R.id.corner_view))\n                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));\n\n        // Check that it is the expected corner view by checking the text\n        // The first child of the RelativeLayout is a textView (index starts at zero)\n        onView(allOf(withParent(withId(R.id.corner_view)), withParentIndex(0)))\n                .check(matches(withText(\"Corner\")));\n\n        // Check that Corner to is to the right of the column headers\n        onView(withId(R.id.corner_view)).check(isCompletelyLeftOf(withId(R.id.ColumnHeaderRecyclerView)));\n\n        // Check that Corner to is to the above of the row headers\n        onView(withId(R.id.corner_view)).check(isCompletelyAbove(withId(R.id.RowHeaderRecyclerView)));\n\n        // Check that the corner is new width\n        onView(withId(R.id.corner_view)).check(matches(new ViewWidthMatcher(200)));\n\n        // Check that the row header is new width\n        onView(withId(R.id.RowHeaderRecyclerView)).check(matches(new ViewWidthMatcher(200)));\n    }\n\n    @Test\n    public void testSetRowHeaderWidthRight() {\n        mActivityTestRule.getScenario()\n                .onActivity(activity -> {\n                    activity.setContentView(R.layout.corner_top_right);\n\n                    TableView tableView = activity.findViewById(R.id.tableview);\n\n                    CornerTestAdapter cornerTestAdapter = new CornerTestAdapter();\n\n                    tableView.setAdapter(cornerTestAdapter);\n\n                    SimpleData simpleData = new SimpleData(5);\n\n                    cornerTestAdapter.setAllItems(\n                            simpleData.getColumnHeaders(), simpleData.getRowHeaders(), simpleData.getCells());\n\n                    // Set a new width on row header\n                    tableView.setRowHeaderWidth(200);\n                });\n\n        // Check that the corner view is created and visible\n        // The Corner view uses cell_layout which has RelativeLayout as top item\n        onView(withId(R.id.corner_view))\n                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));\n\n        // Check that it is the expected corner view by checking the text\n        // The first child of the RelativeLayout is a textView (index starts at zero)\n        onView(allOf(withParent(withId(R.id.corner_view)), withParentIndex(0)))\n                .check(matches(withText(\"Corner\")));\n\n        // Check that Corner to is to the right of the column headers\n        onView(withId(R.id.corner_view)).check(isCompletelyRightOf(withId(R.id.ColumnHeaderRecyclerView)));\n\n        // Check that Corner to is to the above of the row headers\n        onView(withId(R.id.corner_view)).check(isCompletelyAbove(withId(R.id.RowHeaderRecyclerView)));\n\n        // Check that the corner is new width\n        onView(withId(R.id.corner_view)).check(matches(new ViewWidthMatcher(200)));\n\n        // Check that the row header is new width\n        onView(withId(R.id.RowHeaderRecyclerView)).check(matches(new ViewWidthMatcher(200)));\n    }\n}\n"
  },
  {
    "path": "tableview/src/androidTest/java/com/evrencoskun/tableview/test/CornerViewTest.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Andrew Beck\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.test;\n\nimport static androidx.test.espresso.Espresso.onView;\nimport static androidx.test.espresso.assertion.ViewAssertions.matches;\nimport static androidx.test.espresso.matcher.ViewMatchers.Visibility;\nimport static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;\nimport static androidx.test.espresso.matcher.ViewMatchers.withId;\nimport static androidx.test.espresso.matcher.ViewMatchers.withText;\n\nimport android.widget.RelativeLayout;\n\nimport androidx.test.ext.junit.rules.ActivityScenarioRule;\nimport androidx.test.ext.junit.runners.AndroidJUnit4;\n\nimport com.evrencoskun.tableview.TableView;\nimport com.evrencoskun.tableview.test.adapters.SimpleTestAdapter;\nimport com.evrencoskun.tableview.test.data.SimpleData;\n\nimport org.junit.Assert;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\n@RunWith(AndroidJUnit4.class)\npublic class CornerViewTest {\n\n    @Rule\n    public ActivityScenarioRule<TestActivity> mActivityTestRule =\n            new ActivityScenarioRule<>(TestActivity.class);\n\n    @Test\n    public void testEmptyTable() {\n        mActivityTestRule.getScenario()\n                .onActivity(activity -> {\n                    TableView tableView = new TableView(activity);\n\n                    RelativeLayout rl = new RelativeLayout(activity);\n                    rl.addView(tableView);\n\n                    SimpleTestAdapter simpleTestAdapter = new SimpleTestAdapter();\n\n                    tableView.setAdapter(simpleTestAdapter);\n\n                    SimpleData simpleData = new SimpleData(0);\n\n                    simpleTestAdapter.setAllItems(simpleData.getColumnHeaders(), simpleData.getRowHeaders(),\n                            simpleData.getCells());\n\n                    activity.setContentView(rl);\n\n                    // Check that the corner view is not created (therefore not shown)\n                    Assert.assertNull(simpleTestAdapter.getCornerView());\n                });\n    }\n\n    @Test\n    public void testEmptyTableResetNonEmptyTable() {\n        mActivityTestRule.getScenario()\n                .onActivity(activity -> {\n                    TableView tableView = new TableView(activity);\n\n                    RelativeLayout rl = new RelativeLayout(activity);\n                    rl.addView(tableView);\n\n                    SimpleTestAdapter simpleTestAdapter = new SimpleTestAdapter();\n\n                    tableView.setAdapter(simpleTestAdapter);\n\n                    SimpleData simpleData = new SimpleData(0);\n\n                    simpleTestAdapter.setAllItems(simpleData.getColumnHeaders(), simpleData.getRowHeaders(),\n                            simpleData.getCells());\n\n                    activity.setContentView(rl);\n\n                    // Check that the corner view is not created (therefore not shown)\n                    Assert.assertNull(simpleTestAdapter.getCornerView());\n\n                    // Change the items of data to reset\n                    SimpleData simpleDataReset = new SimpleData(2);\n\n                    simpleTestAdapter.setAllItems(simpleDataReset.getColumnHeaders(), simpleDataReset.getRowHeaders(),\n                            simpleDataReset.getCells());\n\n                    // Check that the corner view is now created\n                    Assert.assertNotNull(simpleTestAdapter.getCornerView());\n                });\n\n        // Check the corner view is now visible\n        onView(withId(R.id.corner_view))\n                .check(matches(withEffectiveVisibility(Visibility.VISIBLE)));\n\n        // Check that it is the expected corner view by checking the text\n        onView(withId(R.id.corner_text))\n                .check(matches(withText(\"Corner\")));\n    }\n\n    @Test\n    public void testEmptyTableResetEmptyTable() {\n        mActivityTestRule.getScenario()\n                .onActivity(activity -> {\n                    TableView tableView = new TableView(activity);\n\n                    RelativeLayout rl = new RelativeLayout(activity);\n                    rl.addView(tableView);\n\n                    SimpleTestAdapter simpleTestAdapter = new SimpleTestAdapter();\n\n                    tableView.setAdapter(simpleTestAdapter);\n\n                    SimpleData simpleData = new SimpleData(0);\n\n                    simpleTestAdapter.setAllItems(simpleData.getColumnHeaders(), simpleData.getRowHeaders(),\n                            simpleData.getCells());\n\n                    activity.setContentView(rl);\n\n                    // Check that the corner view is not created (therefore not shown)\n                    Assert.assertNull(simpleTestAdapter.getCornerView());\n\n                    // Change the items of data to reset\n                    SimpleData simpleDataReset = new SimpleData(0);\n\n                    simpleTestAdapter.setAllItems(simpleDataReset.getColumnHeaders(), simpleDataReset.getRowHeaders(),\n                            simpleDataReset.getCells());\n\n                    // Check that the corner view is still not created\n                    Assert.assertNull(simpleTestAdapter.getCornerView());\n                });\n    }\n\n    @Test\n    public void testNonEmptyTable() {\n        mActivityTestRule.getScenario()\n                .onActivity(activity -> {\n                    TableView tableView = new TableView(activity);\n\n                    RelativeLayout rl = new RelativeLayout(activity);\n                    rl.addView(tableView);\n\n                    SimpleTestAdapter simpleTestAdapter = new SimpleTestAdapter();\n\n                    tableView.setAdapter(simpleTestAdapter);\n\n                    SimpleData simpleData = new SimpleData(1);\n\n                    simpleTestAdapter.setAllItems(simpleData.getColumnHeaders(), simpleData.getRowHeaders(),\n                            simpleData.getCells());\n\n                    activity.setContentView(rl);\n\n                    // Check that the corner view is created\n                    Assert.assertNotNull(simpleTestAdapter.getCornerView());\n                });\n\n        // Check the corner view is now visible\n        onView(withId(R.id.corner_view))\n                .check(matches(withEffectiveVisibility(Visibility.VISIBLE)));\n\n        // Check that it is the expected corner view by checking the text\n        onView(withId(R.id.corner_text))\n                .check(matches(withText(\"Corner\")));\n    }\n\n    @Test\n    public void testNonEmptyTableResetNonEmpty() {\n        mActivityTestRule.getScenario()\n                .onActivity(activity -> {\n                    TableView tableView = new TableView(activity);\n                    tableView.setId(R.id.tableview);\n\n                    RelativeLayout rl = new RelativeLayout(activity);\n                    rl.addView(tableView);\n\n                    SimpleTestAdapter simpleTestAdapter = new SimpleTestAdapter();\n\n                    tableView.setAdapter(simpleTestAdapter);\n\n                    SimpleData simpleData = new SimpleData(1);\n\n                    simpleTestAdapter.setAllItems(simpleData.getColumnHeaders(), simpleData.getRowHeaders(),\n                            simpleData.getCells());\n\n                    activity.setContentView(rl);\n\n                    // Check that the corner view is created before resetting to empty\n                    Assert.assertNotNull(simpleTestAdapter.getCornerView());\n                });\n\n        // Check the corner view is visible\n        onView(withId(R.id.corner_view))\n                .check(matches(withEffectiveVisibility(Visibility.VISIBLE)));\n\n        mActivityTestRule.getScenario()\n                .onActivity(activity -> {\n                    TableView tableView = activity.findViewById(R.id.tableview);\n\n                    SimpleTestAdapter simpleTestAdapter = (SimpleTestAdapter) tableView.getAdapter();\n\n                    // Change the items of data to reset\n                    SimpleData simpleDataReset = new SimpleData(2);\n\n                    simpleTestAdapter.setAllItems(simpleDataReset.getColumnHeaders(), simpleDataReset.getRowHeaders(),\n                            simpleDataReset.getCells());\n\n                    // Check that the corner view is still created\n                    Assert.assertNotNull(simpleTestAdapter.getCornerView());\n                });\n\n        // Check the corner view is still visible\n        onView(withId(R.id.corner_view))\n                .check(matches(withEffectiveVisibility(Visibility.VISIBLE)));\n\n        // Check that it is the expected corner view by checking the text\n        onView(withId(R.id.corner_text))\n                .check(matches(withText(\"Corner\")));\n    }\n\n    @Test\n    public void testNonEmptyTableResetEmpty() {\n        mActivityTestRule.getScenario()\n                .onActivity(activity -> {\n                    TableView tableView = new TableView(activity);\n\n                    RelativeLayout rl = new RelativeLayout(activity);\n                    rl.addView(tableView);\n\n                    SimpleTestAdapter simpleTestAdapter = new SimpleTestAdapter();\n\n                    tableView.setAdapter(simpleTestAdapter);\n\n                    SimpleData simpleData = new SimpleData(1);\n\n                    simpleTestAdapter.setAllItems(simpleData.getColumnHeaders(), simpleData.getRowHeaders(),\n                            simpleData.getCells());\n\n                    // Check that the corner view is created before resetting to empty\n                    Assert.assertNotNull(simpleTestAdapter.getCornerView());\n\n                    // Change the items of data to reset\n                    SimpleData simpleDataReset = new SimpleData(0);\n\n                    simpleTestAdapter.setAllItems(simpleDataReset.getColumnHeaders(), simpleDataReset.getRowHeaders(),\n                            simpleDataReset.getCells());\n\n                    activity.setContentView(rl);\n\n                    // Check that the corner view is still created but visibility is gone\n                    Assert.assertNotNull(simpleTestAdapter.getCornerView());\n                });\n\n        // Check the corner view visibility is GONE\n        onView(withId(R.id.corner_view))\n                .check(matches(withEffectiveVisibility(Visibility.GONE)));\n    }\n\n    @Test\n    public void testColumnHeadersOnlyTable() {\n        mActivityTestRule.getScenario()\n                .onActivity(activity -> {\n                    TableView tableView = new TableView(activity);\n\n                    RelativeLayout rl = new RelativeLayout(activity);\n                    rl.addView(tableView);\n\n                    SimpleTestAdapter simpleTestAdapter = new SimpleTestAdapter();\n\n                    tableView.setAdapter(simpleTestAdapter);\n\n                    // Only want column headers\n                    SimpleData simpleData = new SimpleData(5, 0);\n\n                    simpleTestAdapter.setAllItems(simpleData.getColumnHeaders(), simpleData.getRowHeaders(),\n                            simpleData.getCells());\n\n                    activity.setContentView(rl);\n\n                    // Check that the corner view is not created\n                    Assert.assertNull(simpleTestAdapter.getCornerView());\n                });\n    }\n\n    @Test\n    public void testColumnHeadersOnlyTableResetNonEmptyTable() {\n        mActivityTestRule.getScenario()\n                .onActivity(activity -> {\n                    TableView tableView = new TableView(activity);\n\n                    RelativeLayout rl = new RelativeLayout(activity);\n                    rl.addView(tableView);\n\n                    SimpleTestAdapter simpleTestAdapter = new SimpleTestAdapter();\n\n                    tableView.setAdapter(simpleTestAdapter);\n\n                    // Only want column headers\n                    SimpleData simpleData = new SimpleData(5, 0);\n\n                    simpleTestAdapter.setAllItems(simpleData.getColumnHeaders(), simpleData.getRowHeaders(),\n                            simpleData.getCells());\n\n                    // Check that the corner view is not created\n                    Assert.assertNull(simpleTestAdapter.getCornerView());\n\n                    // Change the items of data to reset\n                    SimpleData simpleDataReset = new SimpleData(5);\n\n                    simpleTestAdapter.setAllItems(simpleDataReset.getColumnHeaders(), simpleDataReset.getRowHeaders(),\n                            simpleDataReset.getCells());\n\n                    activity.setContentView(rl);\n\n                    // Check that the corner view is not created\n                    Assert.assertNotNull(simpleTestAdapter.getCornerView());\n                });\n\n        // Check the corner view is now visible\n        onView(withId(R.id.corner_view))\n                .check(matches(withEffectiveVisibility(Visibility.VISIBLE)));\n\n        // Check that it is the expected corner view by checking the text\n        onView(withId(R.id.corner_text))\n                .check(matches(withText(\"Corner\")));\n    }\n\n    @Test\n    public void testColumnHeadersOnlyTableResetEmptyTable() {\n        mActivityTestRule.getScenario()\n                .onActivity(activity -> {\n                    TableView tableView = new TableView(activity);\n\n                    RelativeLayout rl = new RelativeLayout(activity);\n                    rl.addView(tableView);\n\n                    SimpleTestAdapter simpleTestAdapter = new SimpleTestAdapter();\n\n                    tableView.setAdapter(simpleTestAdapter);\n\n                    // Only want column headers\n                    SimpleData simpleData = new SimpleData(5, 0);\n\n                    simpleTestAdapter.setAllItems(simpleData.getColumnHeaders(), simpleData.getRowHeaders(),\n                            simpleData.getCells());\n\n                    // Check that the corner view is not created\n                    Assert.assertNull(simpleTestAdapter.getCornerView());\n\n                    // Change the items of data to reset\n                    SimpleData simpleDataReset = new SimpleData(0);\n\n                    simpleTestAdapter.setAllItems(simpleDataReset.getColumnHeaders(), simpleDataReset.getRowHeaders(),\n                            simpleDataReset.getCells());\n\n                    activity.setContentView(rl);\n\n                    // Check that the corner view is not created\n                    Assert.assertNull(simpleTestAdapter.getCornerView());\n                });\n    }\n\n    @Test\n    public void testColumnHeadersOnlyTableShowCorner() {\n        mActivityTestRule.getScenario()\n                .onActivity(activity -> {\n                    TableView tableView = new TableView(activity);\n\n                    RelativeLayout rl = new RelativeLayout(activity);\n                    rl.addView(tableView);\n\n                    // Set the option to show corner view when there is not row data\n                    tableView.setShowCornerView(true);\n\n                    SimpleTestAdapter simpleTestAdapter = new SimpleTestAdapter();\n\n                    tableView.setAdapter(simpleTestAdapter);\n\n                    // Only want column headers\n                    SimpleData simpleData = new SimpleData(5, 0);\n\n                    simpleTestAdapter.setAllItems(simpleData.getColumnHeaders(), simpleData.getRowHeaders(),\n                            simpleData.getCells());\n\n                    activity.setContentView(rl);\n\n                    // Check that the corner view is created\n                    Assert.assertNotNull(simpleTestAdapter.getCornerView());\n                });\n\n        // Check the corner view is now visible\n        onView(withId(R.id.corner_view))\n                .check(matches(withEffectiveVisibility(Visibility.VISIBLE)));\n\n        // Check that it is the expected corner view by checking the text\n        onView(withId(R.id.corner_text))\n                .check(matches(withText(\"Corner\")));\n    }\n\n    @Test\n    public void testColumnHeadersOnlyTableShowCornerResetEmptyTable() {\n        mActivityTestRule.getScenario()\n                .onActivity(activity -> {\n                    TableView tableView = new TableView(activity);\n\n                    RelativeLayout rl = new RelativeLayout(activity);\n                    rl.addView(tableView);\n\n                    // Set the option to show corner view when there is not row data\n                    tableView.setShowCornerView(true);\n\n                    SimpleTestAdapter simpleTestAdapter = new SimpleTestAdapter();\n\n                    tableView.setAdapter(simpleTestAdapter);\n\n                    // Only want column headers\n                    SimpleData simpleData = new SimpleData(5, 0);\n\n                    simpleTestAdapter.setAllItems(simpleData.getColumnHeaders(), simpleData.getRowHeaders(),\n                            simpleData.getCells());\n\n                    // Check that the corner view is created\n                    Assert.assertNotNull(simpleTestAdapter.getCornerView());\n\n                    // Change the items of data to reset\n                    SimpleData simpleDataReset = new SimpleData(0);\n\n                    simpleTestAdapter.setAllItems(simpleDataReset.getColumnHeaders(), simpleDataReset.getRowHeaders(),\n                            simpleDataReset.getCells());\n\n                    activity.setContentView(rl);\n\n                    // Check that the corner view is still created\n                    Assert.assertNotNull(simpleTestAdapter.getCornerView());\n                });\n\n        // Check the corner view visibility is GONE\n        onView(withId(R.id.corner_view))\n                .check(matches(withEffectiveVisibility(Visibility.GONE)));\n    }\n\n    @Test\n    public void testColumnHeadersOnlyTableShowCornerResetNonEmptyTable() {\n        mActivityTestRule.getScenario()\n                .onActivity(activity -> {\n                    TableView tableView = new TableView(activity);\n\n                    RelativeLayout rl = new RelativeLayout(activity);\n                    rl.addView(tableView);\n\n                    // Set the option to show corner view when there is not row data\n                    tableView.setShowCornerView(true);\n\n                    SimpleTestAdapter simpleTestAdapter = new SimpleTestAdapter();\n\n                    tableView.setAdapter(simpleTestAdapter);\n\n                    // Only want column headers\n                    SimpleData simpleData = new SimpleData(5, 0);\n\n                    simpleTestAdapter.setAllItems(simpleData.getColumnHeaders(), simpleData.getRowHeaders(),\n                            simpleData.getCells());\n\n                    // Check that the corner view is created\n                    Assert.assertNotNull(simpleTestAdapter.getCornerView());\n\n                    // Change the items of data to reset\n                    SimpleData simpleDataReset = new SimpleData(2);\n                    simpleTestAdapter.setAllItems(simpleDataReset.getColumnHeaders(), simpleDataReset.getRowHeaders(),\n                            simpleDataReset.getCells());\n\n                    activity.setContentView(rl);\n\n                    // Check that the corner view is still created\n                    Assert.assertNotNull(simpleTestAdapter.getCornerView());\n                });\n\n        // Check the corner view visibility is VISIBLE\n        onView(withId(R.id.corner_view))\n                .check(matches(withEffectiveVisibility(Visibility.VISIBLE)));\n    }\n}\n"
  },
  {
    "path": "tableview/src/androidTest/java/com/evrencoskun/tableview/test/ReverseLayoutTest.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2020 Andrew Beck\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.test;\n\nimport static androidx.test.espresso.Espresso.onView;\nimport static androidx.test.espresso.assertion.PositionAssertions.isCompletelyLeftOf;\nimport static androidx.test.espresso.assertion.PositionAssertions.isCompletelyRightOf;\nimport static androidx.test.espresso.assertion.ViewAssertions.matches;\nimport static androidx.test.espresso.matcher.ViewMatchers.Visibility;\nimport static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;\nimport static androidx.test.espresso.matcher.ViewMatchers.withId;\nimport static androidx.test.espresso.matcher.ViewMatchers.withParent;\nimport static androidx.test.espresso.matcher.ViewMatchers.withParentIndex;\nimport static androidx.test.espresso.matcher.ViewMatchers.withText;\nimport static org.hamcrest.Matchers.allOf;\n\nimport android.widget.RelativeLayout;\n\nimport androidx.test.ext.junit.rules.ActivityScenarioRule;\nimport androidx.test.ext.junit.runners.AndroidJUnit4;\n\nimport com.evrencoskun.tableview.ITableView;\nimport com.evrencoskun.tableview.TableView;\nimport com.evrencoskun.tableview.test.adapters.CornerTestAdapter;\nimport com.evrencoskun.tableview.test.data.SimpleData;\n\nimport org.junit.Assert;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\n@RunWith(AndroidJUnit4.class)\npublic class ReverseLayoutTest {\n\n    @Rule\n    public ActivityScenarioRule<TestActivity> mActivityTestRule =\n            new ActivityScenarioRule<>(TestActivity.class);\n\n    @Test\n    public void testDefaultLayout() {\n        mActivityTestRule.getScenario()\n                .onActivity(activity -> {\n                    activity.setContentView(R.layout.corner_default);\n\n                    TableView tableView = activity.findViewById(R.id.tableview);\n                    Assert.assertNotNull(tableView);\n\n                    CornerTestAdapter cornerTestAdapter = new CornerTestAdapter();\n\n                    tableView.setAdapter(cornerTestAdapter);\n\n                    SimpleData simpleData = new SimpleData(5);\n\n                    cornerTestAdapter.setAllItems(\n                            simpleData.getColumnHeaders(), simpleData.getRowHeaders(), simpleData.getCells());\n                });\n\n        // Check that the corner view is created and visible\n        // The Corner view uses cell_layout which has RelativeLayout as top item\n        onView(withId(R.id.corner_view))\n                .check(matches(withEffectiveVisibility(Visibility.VISIBLE)));\n\n        // Check that it is the expected corner view by checking the text\n        // The first child of the RelativeLayout is a textView (index starts at zero)\n        onView(allOf(withParent(withId(R.id.corner_view)), withParentIndex(0)))\n                .check(matches(withText(\"Corner\")));\n\n        // Check that column headers are ordered Left to Right\n        onView(withText(\"c:0\")).check(isCompletelyLeftOf(withText(\"c:1\")));\n\n        // Check that first cell data row are ordered Left to Right\n        onView(withText(\"r:0c:0\")).check(isCompletelyLeftOf(withText(\"r:0c:1\")));\n    }\n\n    @Test\n    public void testReverseLayout() {\n        mActivityTestRule.getScenario()\n                .onActivity(activity -> {\n                    activity.setContentView(R.layout.reverse_layout);\n\n                    TableView tableView = activity.findViewById(R.id.tableview);\n                    Assert.assertNotNull(tableView);\n\n                    CornerTestAdapter cornerTestAdapter = new CornerTestAdapter();\n\n                    tableView.setAdapter(cornerTestAdapter);\n\n                    SimpleData simpleData = new SimpleData(5);\n\n                    cornerTestAdapter.setAllItems(\n                            simpleData.getColumnHeaders(), simpleData.getRowHeaders(), simpleData.getCells());\n                });\n\n        // Check that the corner view is created and visible\n        // The Corner view uses cell_layout which has RelativeLayout as top item\n        onView(withId(R.id.corner_view))\n                .check(matches(withEffectiveVisibility(Visibility.VISIBLE)));\n\n        // Check that it is the expected corner view by checking the text\n        // The first child of the RelativeLayout is a textView (index starts at zero)\n        onView(allOf(withParent(withId(R.id.corner_view)), withParentIndex(0)))\n                .check(matches(withText(\"Corner\")));\n\n        // Check that column headers are ordered Right to Left\n        onView(withText(\"c:0\")).check(isCompletelyRightOf(withText(\"c:1\")));\n\n        // Check that first cell data row are ordered Right to Left\n        onView(withText(\"r:0c:0\")).check(isCompletelyRightOf(withText(\"r:0c:1\")));\n    }\n\n    @Test\n    public void testReverseConstructor() {\n        mActivityTestRule.getScenario()\n                .onActivity(activity -> {\n                    TableView tableView = new TableView(activity, false);\n\n                    // initialize was false so set properties and call initialize\n                    //Set CornerView to Top Right and ReverseLayout = true\n                    tableView.setCornerViewLocation(ITableView.CornerViewLocation.TOP_RIGHT);\n                    tableView.setReverseLayout(true);\n                    tableView.initialize();\n\n                    RelativeLayout rl = new RelativeLayout(activity);\n                    rl.addView(tableView);\n\n                    CornerTestAdapter cornerTestAdapter = new CornerTestAdapter();\n\n                    tableView.setAdapter(cornerTestAdapter);\n\n                    SimpleData simpleData = new SimpleData(5);\n\n                    cornerTestAdapter.setAllItems(\n                            simpleData.getColumnHeaders(), simpleData.getRowHeaders(), simpleData.getCells());\n\n                    activity.setContentView(rl);\n                });\n\n        // Check that the corner view is created and visible\n        // The Corner view uses cell_layout which has RelativeLayout as top item\n        onView(withId(R.id.corner_view))\n                .check(matches(withEffectiveVisibility(Visibility.VISIBLE)));\n\n        // Check that it is the expected corner view by checking the text\n        // The first child of the RelativeLayout is a textView (index starts at zero)\n        onView(allOf(withParent(withId(R.id.corner_view)), withParentIndex(0)))\n                .check(matches(withText(\"Corner\")));\n\n        // Check that column headers are ordered Right to Left\n        onView(withText(\"c:0\")).check(isCompletelyRightOf(withText(\"c:1\")));\n\n        // Check that first cell data row are ordered Right to Left\n        onView(withText(\"r:0c:0\")).check(isCompletelyRightOf(withText(\"r:0c:1\")));\n    }\n}\n"
  },
  {
    "path": "tableview/src/androidTest/java/com/evrencoskun/tableview/test/SimpleActivityTest.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Andrew Beck\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.test;\n\nimport static androidx.test.espresso.Espresso.onView;\nimport static androidx.test.espresso.assertion.ViewAssertions.matches;\nimport static androidx.test.espresso.matcher.ViewMatchers.withId;\nimport static androidx.test.espresso.matcher.ViewMatchers.withParent;\nimport static androidx.test.espresso.matcher.ViewMatchers.withParentIndex;\nimport static androidx.test.espresso.matcher.ViewMatchers.withText;\nimport static org.hamcrest.Matchers.allOf;\n\nimport android.view.View;\nimport android.widget.RelativeLayout;\n\nimport androidx.test.ext.junit.rules.ActivityScenarioRule;\nimport androidx.test.ext.junit.runners.AndroidJUnit4;\nimport androidx.test.platform.app.InstrumentationRegistry;\n\nimport com.evrencoskun.tableview.TableView;\nimport com.evrencoskun.tableview.test.adapters.SimpleTestAdapter;\nimport com.evrencoskun.tableview.test.data.SimpleData;\n\nimport org.hamcrest.Matcher;\nimport org.junit.Assert;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\n@RunWith(AndroidJUnit4.class)\npublic class SimpleActivityTest {\n\n    @Rule\n    public ActivityScenarioRule<TestActivity> mActivityTestRule =\n            new ActivityScenarioRule<>(TestActivity.class);\n\n    @Test\n    public void testDefaults() {\n        TableView tableView =\n                new TableView(InstrumentationRegistry.getInstrumentation().getTargetContext());\n        Assert.assertFalse(tableView.isAllowClickInsideCell());\n        Assert.assertTrue(tableView.isShowHorizontalSeparators());\n        Assert.assertTrue(tableView.isShowVerticalSeparators());\n    }\n\n    @Test\n    public void testSmallTable() {\n        mActivityTestRule.getScenario()\n                .onActivity(activity -> {\n                    TableView tableView = new TableView(activity);\n                    tableView.setId(R.id.tableview);\n\n                    RelativeLayout rl = new RelativeLayout(activity);\n                    rl.addView(tableView);\n\n                    SimpleTestAdapter simpleTestAdapter = new SimpleTestAdapter();\n\n                    tableView.setAdapter(simpleTestAdapter);\n\n                    SimpleData simpleData = new SimpleData(5);\n\n                    simpleTestAdapter.setAllItems(\n                            simpleData.getColumnHeaders(), simpleData.getRowHeaders(), simpleData.getCells());\n\n                    activity.setContentView(rl);\n                });\n\n        // Check that the row header was created as expected at 5th Row (index starts at zero)\n        // cell_layout has LinearLayout as top item\n        Matcher<View> rowHeaders = allOf(withParent(withId(R.id.tableview)), withParentIndex(1));\n        Matcher<View> rowHeader = allOf(withParent(rowHeaders), withParentIndex(4));\n\n        onView(allOf(withParent(rowHeader), withParentIndex(0)))\n                .check(matches(withText(\"r:4\")));\n\n        // Check that the column header was created as expected at 5th Row (index starts at zero)\n        // cell_layout has LinearLayout as top item\n        Matcher<View> columnHeaders = allOf(withParent(withId(R.id.tableview)), withParentIndex(0));\n        Matcher<View> columnHeader = allOf(withParent(columnHeaders), withParentIndex(4));\n\n        onView(allOf(withParent(columnHeader), withParentIndex(0)))\n                .check(matches(withText(\"c:4\")));\n    }\n}\n"
  },
  {
    "path": "tableview/src/androidTest/java/com/evrencoskun/tableview/test/TestActivity.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Andrew Beck\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.test;\n\nimport android.app.Activity;\n\npublic class TestActivity extends Activity {\n}\n"
  },
  {
    "path": "tableview/src/androidTest/java/com/evrencoskun/tableview/test/adapters/AbstractTableAdapterTest.java",
    "content": "package com.evrencoskun.tableview.test.adapters;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static java.util.Collections.emptyList;\n\nimport android.view.View;\n\nimport androidx.test.ext.junit.rules.ActivityScenarioRule;\nimport androidx.test.ext.junit.runners.AndroidJUnit4;\nimport androidx.test.platform.app.InstrumentationRegistry;\n\nimport com.evrencoskun.tableview.TableView;\nimport com.evrencoskun.tableview.test.TestActivity;\nimport com.evrencoskun.tableview.test.data.SimpleData;\n\nimport org.junit.Before;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\n\n@RunWith(AndroidJUnit4.class)\npublic class AbstractTableAdapterTest {\n\n    @Rule\n    public ActivityScenarioRule<TestActivity> mActivityTestRule =\n            new ActivityScenarioRule<>(TestActivity.class);\n\n    private SimpleData mData;\n    private TableView mTableView;\n    private SimpleTestAdapter mAdapter;\n\n    @Before\n    public void before() {\n        mData = new SimpleData(5);\n        mTableView = new TableView(InstrumentationRegistry.getInstrumentation().getContext());\n\n        mAdapter = new SimpleTestAdapter();\n        mAdapter.setTableView(mTableView);\n    }\n\n    @Test\n    public void testCornerViewStateWithDisabledCorner() {\n        mTableView.setShowCornerView(false);\n\n        assertNull(mAdapter.getCornerView());\n\n        mAdapter.setAllItems(null, null, null);\n\n        assertNull(mAdapter.getCornerView());\n\n        mAdapter.setAllItems(mData.getColumnHeaders(), mData.getRowHeaders(), mData.getCells());\n\n        assertNotNull(mAdapter.getCornerView());\n        assertEquals(View.VISIBLE, mAdapter.getCornerView().getVisibility());\n\n        mAdapter.setAllItems(emptyList(), emptyList(), emptyList());\n\n        assertNotNull(mAdapter.getCornerView());\n        assertEquals(View.GONE, mAdapter.getCornerView().getVisibility());\n    }\n\n    @Test\n    public void testCornerViewStateWithEnabledCorners() {\n        mTableView.setShowCornerView(true);\n\n        assertNull(mAdapter.getCornerView());\n\n        mAdapter.setAllItems(mData.getColumnHeaders(), mData.getRowHeaders(), mData.getCells());\n\n        assertNotNull(mAdapter.getCornerView());\n        assertEquals(View.VISIBLE, mAdapter.getCornerView().getVisibility());\n\n        mAdapter.setAllItems(null, null, null);\n\n        assertNotNull(mAdapter.getCornerView());\n        assertEquals(View.GONE, mAdapter.getCornerView().getVisibility());\n\n        // We set some data, that we then reset to empty\n        mAdapter.setAllItems(mData.getColumnHeaders(), mData.getRowHeaders(), mData.getCells());\n        mAdapter.setAllItems(emptyList(), emptyList(), emptyList());\n\n        assertNotNull(mAdapter.getCornerView());\n        assertEquals(View.GONE, mAdapter.getCornerView().getVisibility());\n\n        mAdapter.setAllItems(mData.getColumnHeaders(), null, null);\n\n        assertNotNull(mAdapter.getCornerView());\n        assertEquals(View.VISIBLE, mAdapter.getCornerView().getVisibility());\n\n        mAdapter.setAllItems(null, mData.getRowHeaders(), null);\n\n        assertNotNull(mAdapter.getCornerView());\n        assertEquals(View.GONE, mAdapter.getCornerView().getVisibility());\n\n        mAdapter.setAllItems(mData.getColumnHeaders(), mData.getRowHeaders(), null);\n\n        assertNotNull(mAdapter.getCornerView());\n        assertEquals(View.VISIBLE, mAdapter.getCornerView().getVisibility());\n    }\n\n    @Test\n    public void testCornerViewStateWithToggledCorners() {\n        mTableView.setShowCornerView(true);\n\n        assertNull(mAdapter.getCornerView());\n\n        mAdapter.setAllItems(mData.getColumnHeaders(), mData.getRowHeaders(), mData.getCells());\n\n        assertNotNull(mAdapter.getCornerView());\n        assertEquals(View.VISIBLE, mAdapter.getCornerView().getVisibility());\n\n        mTableView.setShowCornerView(false);\n        mAdapter.setAllItems(mData.getColumnHeaders(), mData.getRowHeaders(), mData.getCells());\n\n        assertNotNull(mAdapter.getCornerView());\n        assertEquals(View.VISIBLE, mAdapter.getCornerView().getVisibility());\n\n        mAdapter.setAllItems(null, null, null);\n\n        assertNotNull(mAdapter.getCornerView());\n        assertEquals(View.GONE, mAdapter.getCornerView().getVisibility());\n\n        // We set some data, that we then reset to empty\n        mAdapter.setAllItems(mData.getColumnHeaders(), mData.getRowHeaders(), mData.getCells());\n        mAdapter.setAllItems(emptyList(), emptyList(), emptyList());\n\n        assertNotNull(mAdapter.getCornerView());\n        assertEquals(View.GONE, mAdapter.getCornerView().getVisibility());\n\n        mAdapter.setAllItems(mData.getColumnHeaders(), null, null);\n\n        assertNotNull(mAdapter.getCornerView());\n        assertEquals(View.GONE, mAdapter.getCornerView().getVisibility());\n\n        mAdapter.setAllItems(null, mData.getRowHeaders(), null);\n\n        assertNotNull(mAdapter.getCornerView());\n        assertEquals(View.GONE, mAdapter.getCornerView().getVisibility());\n\n        mAdapter.setAllItems(mData.getColumnHeaders(), mData.getRowHeaders(), null);\n\n        assertNotNull(mAdapter.getCornerView());\n        assertEquals(View.VISIBLE, mAdapter.getCornerView().getVisibility());\n    }\n}\n"
  },
  {
    "path": "tableview/src/androidTest/java/com/evrencoskun/tableview/test/adapters/CornerTestAdapter.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Andrew Beck\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.test.adapters;\n\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\n\nimport com.evrencoskun.tableview.test.R;\nimport com.evrencoskun.tableview.adapter.AbstractTableAdapter;\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder;\nimport com.evrencoskun.tableview.test.models.Cell;\nimport com.evrencoskun.tableview.test.models.ColumnHeader;\nimport com.evrencoskun.tableview.test.models.RowHeader;\n\npublic class CornerTestAdapter extends AbstractTableAdapter<ColumnHeader, RowHeader, Cell> {\n\n    static class TestCellViewHolder extends AbstractViewHolder {\n\n        final LinearLayout cell_container;\n        final TextView cell_textview;\n\n        TestCellViewHolder(View itemView) {\n            super(itemView);\n            cell_container = itemView.findViewById(com.evrencoskun.tableview.test.R.id.cell_container);\n            cell_textview = itemView.findViewById(com.evrencoskun.tableview.test.R.id.cell_data);\n        }\n    }\n\n    @NonNull\n    public AbstractViewHolder onCreateCellViewHolder(@NonNull ViewGroup parent, int viewType) {\n        View layout = LayoutInflater.from(parent.getContext())\n                .inflate(R.layout.cell_layout, parent, false);\n        return new TestCellViewHolder(layout);\n    }\n\n    public void onBindCellViewHolder(@NonNull AbstractViewHolder holder, Cell cell, int\n            columnPosition, int rowPosition) {\n\n        TestCellViewHolder viewHolder = (TestCellViewHolder) holder;\n        viewHolder.cell_textview.setText(cell.getData() != null ? cell.getData().toString() : \"\");\n\n        viewHolder.cell_container.getLayoutParams().width = LinearLayout.LayoutParams.WRAP_CONTENT;\n        viewHolder.cell_textview.requestLayout();\n    }\n\n    static class TestColumnHeaderViewHolder extends AbstractViewHolder {\n\n        final LinearLayout column_header_container;\n        final TextView cell_textview;\n\n        public TestColumnHeaderViewHolder(View itemView) {\n            super(itemView);\n            column_header_container = itemView.findViewById(R.id.column_header_container);\n            cell_textview = itemView.findViewById(R.id.column_header_textView);\n        }\n    }\n\n    @NonNull\n    public AbstractViewHolder onCreateColumnHeaderViewHolder(@NonNull ViewGroup parent, int\n            viewType) {\n        View layout = LayoutInflater.from(parent.getContext())\n                .inflate(R.layout.column_layout, parent, false);\n        return new TestColumnHeaderViewHolder(layout);\n    }\n\n    public void onBindColumnHeaderViewHolder(@NonNull AbstractViewHolder holder,\n                                             ColumnHeader columnHeader, int position) {\n\n        TestColumnHeaderViewHolder viewHolder = (TestColumnHeaderViewHolder) holder;\n        if (columnHeader.getData() != null)\n        viewHolder.cell_textview.setText(columnHeader.getData().toString());\n\n        viewHolder.column_header_container.getLayoutParams().width = LinearLayout.LayoutParams.WRAP_CONTENT;\n        viewHolder.cell_textview.requestLayout();\n    }\n\n\n    static class TestRowHeaderViewHolder extends AbstractViewHolder {\n\n        final TextView cell_textview;\n\n        public TestRowHeaderViewHolder(View itemView) {\n            super(itemView);\n            cell_textview = itemView.findViewById(R.id.row_header_textView);\n        }\n    }\n\n    @NonNull\n    public AbstractViewHolder onCreateRowHeaderViewHolder(@NonNull ViewGroup parent, int viewType) {\n        View layout = LayoutInflater.from(parent.getContext())\n                .inflate(R.layout.row_layout, parent, false);\n        return new TestRowHeaderViewHolder(layout);\n    }\n\n\n    public void onBindRowHeaderViewHolder(@NonNull AbstractViewHolder holder,\n                                          RowHeader rowHeader, int position) {\n\n        TestRowHeaderViewHolder viewHolder = (TestRowHeaderViewHolder) holder;\n        if (rowHeader.getData() != null)\n        viewHolder.cell_textview.setText(rowHeader.getData().toString());\n    }\n\n    @NonNull\n    public View onCreateCornerView(@NonNull ViewGroup parent) {\n        return LayoutInflater.from(parent.getContext())\n                .inflate(R.layout.corner_layout, parent, false);\n    }\n}\n"
  },
  {
    "path": "tableview/src/androidTest/java/com/evrencoskun/tableview/test/adapters/SimpleTestAdapter.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Andrew Beck\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.test.adapters;\n\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\n\nimport com.evrencoskun.tableview.test.R;\nimport com.evrencoskun.tableview.adapter.AbstractTableAdapter;\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder;\nimport com.evrencoskun.tableview.test.models.Cell;\nimport com.evrencoskun.tableview.test.models.ColumnHeader;\nimport com.evrencoskun.tableview.test.models.RowHeader;\n\npublic class SimpleTestAdapter extends AbstractTableAdapter<ColumnHeader, RowHeader, Cell> {\n\n    static class TestCellViewHolder extends AbstractViewHolder {\n\n        final LinearLayout cell_container;\n        final TextView cell_textview;\n\n        TestCellViewHolder(View itemView) {\n            super(itemView);\n            cell_container = itemView.findViewById(com.evrencoskun.tableview.test.R.id.cell_container);\n            cell_textview = itemView.findViewById(com.evrencoskun.tableview.test.R.id.cell_data);\n        }\n    }\n\n    @NonNull\n    public AbstractViewHolder onCreateCellViewHolder(@NonNull ViewGroup parent, int viewType) {\n        View layout = LayoutInflater.from(parent.getContext())\n                .inflate(R.layout.cell_layout, parent, false);\n        return new TestCellViewHolder(layout);\n    }\n\n    public void onBindCellViewHolder(@NonNull AbstractViewHolder holder, Cell cell, int\n            columnPosition, int rowPosition) {\n\n        TestCellViewHolder viewHolder = (TestCellViewHolder) holder;\n        viewHolder.cell_textview.setText(cell.getData() != null ? cell.getData().toString() : \"\");\n\n        viewHolder.cell_container.getLayoutParams().width = LinearLayout.LayoutParams.WRAP_CONTENT;\n        viewHolder.cell_textview.requestLayout();\n    }\n\n    @NonNull\n    public AbstractViewHolder onCreateColumnHeaderViewHolder(@NonNull ViewGroup parent, int\n            viewType) {\n        View layout = LayoutInflater.from(parent.getContext())\n                .inflate(R.layout.cell_layout, parent, false);\n        return new TestCellViewHolder(layout);\n    }\n\n    public void onBindColumnHeaderViewHolder(@NonNull AbstractViewHolder holder,\n                                             ColumnHeader columnHeader, int position) {\n\n        TestCellViewHolder viewHolder = (TestCellViewHolder) holder;\n        if (columnHeader.getData() != null)\n        viewHolder.cell_textview.setText(columnHeader.getData().toString());\n\n        viewHolder.cell_container.getLayoutParams().width = LinearLayout.LayoutParams.WRAP_CONTENT;\n        viewHolder.cell_textview.requestLayout();\n    }\n\n    @NonNull\n    public AbstractViewHolder onCreateRowHeaderViewHolder(@NonNull ViewGroup parent, int viewType) {\n        View layout = LayoutInflater.from(parent.getContext())\n                .inflate(R.layout.cell_layout, parent, false);\n        return new TestCellViewHolder(layout);\n    }\n\n    public void onBindRowHeaderViewHolder(@NonNull AbstractViewHolder holder,\n                                          RowHeader rowHeader, int position) {\n\n        TestCellViewHolder viewHolder = (TestCellViewHolder) holder;\n        if (rowHeader.getData() != null)\n        viewHolder.cell_textview.setText(rowHeader.getData().toString());\n    }\n\n    @NonNull\n    public View onCreateCornerView(@NonNull ViewGroup parent) {\n        return LayoutInflater.from(parent.getContext())\n                .inflate(R.layout.corner_layout, parent, false);\n    }\n}\n"
  },
  {
    "path": "tableview/src/androidTest/java/com/evrencoskun/tableview/test/data/SimpleData.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Andrew Beck\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.test.data;\n\nimport com.evrencoskun.tableview.test.models.Cell;\nimport com.evrencoskun.tableview.test.models.ColumnHeader;\nimport com.evrencoskun.tableview.test.models.RowHeader;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class SimpleData {\n    private List<List<Cell>> cells;\n    private List<ColumnHeader> columnHeaders;\n    private List<RowHeader> rowHeaders;\n\n    public SimpleData(int size){\n        init(size, size);\n    }\n\n    public SimpleData(int columnSize, int rowSize) {\n        init(columnSize, rowSize);\n    }\n\n    private void init(int columnSize, int rowSize) {\n        rowHeaders = new ArrayList<>();\n        for (int i = 0; i < rowSize; i++) {\n            rowHeaders.add(new RowHeader(String.valueOf(i), \"r:\" + i));\n        }\n\n        columnHeaders = new ArrayList<>();\n        for (int i = 0; i < columnSize; i++) {\n            columnHeaders.add(new ColumnHeader(String.valueOf(i), \"c:\" + i));\n        }\n\n        cells = new ArrayList<>();\n        for (int i = 0; i < rowSize; i++) {\n            ArrayList<Cell> cellList = new ArrayList<>();\n            for (int j = 0; j < columnSize; j++) {\n                String id = j + \":\" + i;\n                cellList.add(new Cell(id, \"r:\" + i + \"c:\" + j));\n            }\n            cells.add(cellList);\n        }\n    }\n\n    public List<List<Cell>> getCells() {\n        return cells;\n    }\n\n    public void setCells(List<List<Cell>> cells) {\n        this.cells = cells;\n    }\n\n    public List<ColumnHeader> getColumnHeaders() {\n        return columnHeaders;\n    }\n\n    public void setColumnHeaders(List<ColumnHeader> columnHeaders) {\n        this.columnHeaders = columnHeaders;\n    }\n\n    public List<RowHeader> getRowHeaders() {\n        return rowHeaders;\n    }\n\n    public void setRowHeaders(List<RowHeader> rowHeaders) {\n        this.rowHeaders = rowHeaders;\n    }\n}"
  },
  {
    "path": "tableview/src/androidTest/java/com/evrencoskun/tableview/test/matchers/ViewWidthMatcher.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Andrew Beck\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.test.matchers;\n\nimport android.view.View;\n\nimport org.hamcrest.Description;\nimport org.hamcrest.TypeSafeMatcher;\n\npublic class ViewWidthMatcher extends TypeSafeMatcher<View> {\n    private final int expectedWidth;\n\n    public ViewWidthMatcher(int expectedWidth) {\n        super(View.class);\n        this.expectedWidth = expectedWidth;\n    }\n\n    @Override\n    protected boolean matchesSafely(View target) {\n        int targetWidth = target.getWidth();\n\n        return targetWidth == expectedWidth;\n    }\n\n    @Override\n    public void describeTo(Description description) {\n        description.appendText(\"with WidthMatcher: \");\n        description.appendValue(expectedWidth);\n    }\n}\n"
  },
  {
    "path": "tableview/src/androidTest/java/com/evrencoskun/tableview/test/models/Cell.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Andrew Beck\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.test.models;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.evrencoskun.tableview.filter.IFilterableModel;\nimport com.evrencoskun.tableview.sort.ISortableModel;\n\npublic class Cell implements ISortableModel, IFilterableModel {\n    @NonNull\n    private String mId;\n    @Nullable\n    private Object mData;\n    @NonNull\n    private String mFilterKeyword;\n\n    public Cell(@NonNull String id, @Nullable Object data) {\n        this.mId = id;\n        this.mData = data;\n        this.mFilterKeyword = String.valueOf(data);\n    }\n\n    /**\n     * This is necessary for sorting process.\n     * See ISortableModel\n     */\n    @NonNull\n    @Override\n    public String getId() {\n        return mId;\n    }\n\n    /**\n     * This is necessary for sorting process.\n     * See ISortableModel\n     */\n    @Nullable\n    @Override\n    public Object getContent() {\n        return mData;\n    }\n\n    @Nullable\n    public Object getData() {\n        return mData;\n    }\n\n    public void setData(@Nullable Object data) {\n        mData = data;\n    }\n\n    @NonNull\n    @Override\n    public String getFilterableKeyword() {\n        return mFilterKeyword;\n    }\n}"
  },
  {
    "path": "tableview/src/androidTest/java/com/evrencoskun/tableview/test/models/ColumnHeader.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Andrew Beck\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.test.models;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\n\npublic class ColumnHeader extends Cell {\n    public ColumnHeader(@NonNull String id, @Nullable String data) {\n        super(id, data);\n    }\n}\n"
  },
  {
    "path": "tableview/src/androidTest/java/com/evrencoskun/tableview/test/models/RowHeader.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Andrew Beck\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.test.models;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\npublic class RowHeader extends Cell {\n    public RowHeader(@NonNull String id, @Nullable String data) {\n        super(id, data);\n    }\n}\n"
  },
  {
    "path": "tableview/src/androidTest/res/layout/cell_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--\n  ~ MIT License\n  ~\n  ~ Copyright (c) 2021 Andrew Beck\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in all\n  ~ copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n  ~ SOFTWARE.\n  -->\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/cell_container\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"@dimen/cell_height\"\n    android:background=\"@android:color/white\"\n    android:gravity=\"center\"\n    android:orientation=\"vertical\">\n\n    <TextView\n        android:id=\"@+id/cell_data\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"center_vertical\"\n        android:gravity=\"center\"\n        android:maxLines=\"1\"\n        android:text=\"Cell Data\"\n        android:textColor=\"@android:color/black\"\n        android:textSize=\"12sp\" />\n\n</LinearLayout>"
  },
  {
    "path": "tableview/src/androidTest/res/layout/column_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ MIT License\n  ~\n  ~ Copyright (c) 2021 Andrew Beck\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in all\n  ~ copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n  ~ SOFTWARE.\n  -->\n<LinearLayout\n    android:id=\"@+id/column_header_container\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"@dimen/default_column_header_height\"\n    android:background=\"@color/cell_background_color\"\n    android:orientation=\"vertical\">\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"horizontal\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_gravity=\"center\"\n            android:layout_marginEnd=\"2dp\"\n            android:layout_marginStart=\"2dp\"\n            android:orientation=\"horizontal\">\n\n            <TextView\n                android:id=\"@+id/column_header_textView\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:layout_gravity=\"center\"\n                android:gravity=\"center\"\n                android:textColor=\"@color/table_view_default_text_color\"\n                android:textSize=\"@dimen/text_size\"\n                android:textStyle=\"bold\"\n                tools:text=\"Header Data\" />\n        </LinearLayout>\n\n        <View\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"2dp\"\n            android:layout_gravity=\"bottom\"\n            android:background=\"@color/header_line_color\" />\n    </FrameLayout>\n</LinearLayout>"
  },
  {
    "path": "tableview/src/androidTest/res/layout/corner_bottom_left.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ MIT License\n  ~\n  ~ Copyright (c) 2021 Andrew Beck\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in all\n  ~ copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n  ~ SOFTWARE.\n  -->\n<RelativeLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <com.evrencoskun.tableview.TableView\n        android:id=\"@+id/tableview\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        app:corner_view_location=\"bottom_left\">\n\n    </com.evrencoskun.tableview.TableView>\n\n</RelativeLayout>"
  },
  {
    "path": "tableview/src/androidTest/res/layout/corner_bottom_right.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ MIT License\n  ~\n  ~ Copyright (c) 2021 Andrew Beck\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in all\n  ~ copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n  ~ SOFTWARE.\n  -->\n<RelativeLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <com.evrencoskun.tableview.TableView\n        android:id=\"@+id/tableview\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        app:corner_view_location=\"bottom_right\">\n\n    </com.evrencoskun.tableview.TableView>\n\n</RelativeLayout>"
  },
  {
    "path": "tableview/src/androidTest/res/layout/corner_default.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ MIT License\n  ~\n  ~ Copyright (c) 2021 Andrew Beck\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in all\n  ~ copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n  ~ SOFTWARE.\n  -->\n<RelativeLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <com.evrencoskun.tableview.TableView\n        android:id=\"@+id/tableview\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n    </com.evrencoskun.tableview.TableView>\n\n</RelativeLayout>"
  },
  {
    "path": "tableview/src/androidTest/res/layout/corner_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ MIT License\n  ~\n  ~ Copyright (c) 2021 Andrew Beck\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in all\n  ~ copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n  ~ SOFTWARE.\n  -->\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/corner_view\"\n    android:layout_width=\"@dimen/default_row_header_width\"\n    android:layout_height=\"@dimen/default_column_header_height\"\n    android:background=\"@android:color/white\">\n\n    <TextView\n        android:id=\"@+id/corner_text\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_centerInParent=\"true\"\n        android:text=\"Corner\"\n        android:textColor=\"@color/table_view_default_text_color\"\n        android:textSize=\"@dimen/text_size\"\n        android:textStyle=\"bold\" />\n\n    <View\n        android:layout_width=\"2dp\"\n        android:layout_height=\"match_parent\"\n        android:layout_alignParentEnd=\"true\"\n        android:background=\"@color/header_line_color\" />\n\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"2dp\"\n        android:layout_alignParentBottom=\"true\"\n        android:background=\"@color/header_line_color\" />\n</RelativeLayout>"
  },
  {
    "path": "tableview/src/androidTest/res/layout/corner_top_left.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ MIT License\n  ~\n  ~ Copyright (c) 2021 Andrew Beck\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in all\n  ~ copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n  ~ SOFTWARE.\n  -->\n<RelativeLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <com.evrencoskun.tableview.TableView\n        android:id=\"@+id/tableview\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        app:corner_view_location=\"top_left\">\n\n    </com.evrencoskun.tableview.TableView>\n\n</RelativeLayout>"
  },
  {
    "path": "tableview/src/androidTest/res/layout/corner_top_right.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ MIT License\n  ~\n  ~ Copyright (c) 2021 Andrew Beck\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in all\n  ~ copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n  ~ SOFTWARE.\n  -->\n<RelativeLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <com.evrencoskun.tableview.TableView\n        android:id=\"@+id/tableview\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        app:corner_view_location=\"top_right\">\n\n    </com.evrencoskun.tableview.TableView>\n\n</RelativeLayout>"
  },
  {
    "path": "tableview/src/androidTest/res/layout/reverse_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <com.evrencoskun.tableview.TableView\n        android:id=\"@+id/tableview\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        app:corner_view_location=\"top_right\"\n        app:reverse_layout=\"true\">\n\n    </com.evrencoskun.tableview.TableView>\n\n</RelativeLayout>"
  },
  {
    "path": "tableview/src/androidTest/res/layout/row_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ MIT License\n  ~\n  ~ Copyright (c) 2021 Andrew Beck\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in all\n  ~ copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n  ~ SOFTWARE.\n  -->\n<RelativeLayout android:id=\"@+id/row_header\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:background=\"@color/cell_background_color\"\n    android:layout_width=\"@dimen/default_row_header_width\"\n    android:layout_height=\"@dimen/cell_height\">\n\n    <LinearLayout\n        android:id=\"@+id/row_header_container\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/row_header_textView\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"center\"\n            android:maxLines=\"1\"\n            android:textColor=\"@color/table_view_default_text_color\"\n            android:textSize=\"@dimen/text_size\"\n            android:textStyle=\"bold\"\n            tools:text=\"Row Data\" />\n    </LinearLayout>\n\n    <View\n        android:layout_width=\"2dp\"\n        android:layout_height=\"match_parent\"\n        android:layout_alignParentEnd=\"true\"\n        android:layout_marginEnd=\"0dp\"\n        android:background=\"@color/header_line_color\" />\n</RelativeLayout>"
  },
  {
    "path": "tableview/src/androidTest/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ MIT License\n  ~\n  ~ Copyright (c) 2021 Andrew Beck\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in all\n  ~ copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n  ~ SOFTWARE.\n  -->\n<resources>\n    <color name=\"cell_background_color\">#ffffff</color>\n    <color name=\"header_line_color\">#0a0a0a</color>\n    <color name=\"table_view_default_text_color\">#0a0a0a</color>\n</resources>\n"
  },
  {
    "path": "tableview/src/androidTest/res/values/dimens.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ MIT License\n  ~\n  ~ Copyright (c) 2021 Andrew Beck\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in all\n  ~ copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n  ~ SOFTWARE.\n  -->\n<resources>\n    <dimen name=\"cell_height\">40dp</dimen>\n    <dimen name=\"text_size\">12sp</dimen>\n\n    <!-- Overriding the default values of the tableView -->\n    <dimen name=\"default_row_header_width\">55dp</dimen>\n    <dimen name=\"default_column_header_height\">40dp</dimen>\n</resources>\n"
  },
  {
    "path": "tableview/src/main/AndroidManifest.xml",
    "content": "<!--\n ~ MIT License\n ~\n ~ Copyright (c) 2021 Evren Coşkun\n ~\n ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n ~ of this software and associated documentation files (the \"Software\"), to deal\n ~ in the Software without restriction, including without limitation the rights\n ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n ~ copies of the Software, and to permit persons to whom the Software is\n ~ furnished to do so, subject to the following conditions:\n ~\n ~ The above copyright notice and this permission notice shall be included in all\n ~ copies or substantial portions of the Software.\n ~\n ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n ~ SOFTWARE.\n  -->\n<manifest package=\"com.evrencoskun.tableview\" />\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/ITableView.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview;\n\nimport android.content.Context;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.recyclerview.widget.DividerItemDecoration;\nimport androidx.recyclerview.widget.LinearLayoutManager;\n\nimport com.evrencoskun.tableview.adapter.AbstractTableAdapter;\nimport com.evrencoskun.tableview.adapter.recyclerview.CellRecyclerView;\nimport com.evrencoskun.tableview.filter.Filter;\nimport com.evrencoskun.tableview.handler.ColumnSortHandler;\nimport com.evrencoskun.tableview.handler.FilterHandler;\nimport com.evrencoskun.tableview.handler.ScrollHandler;\nimport com.evrencoskun.tableview.handler.SelectionHandler;\nimport com.evrencoskun.tableview.handler.VisibilityHandler;\nimport com.evrencoskun.tableview.layoutmanager.CellLayoutManager;\nimport com.evrencoskun.tableview.layoutmanager.ColumnHeaderLayoutManager;\nimport com.evrencoskun.tableview.listener.ITableViewListener;\nimport com.evrencoskun.tableview.listener.scroll.HorizontalRecyclerViewListener;\nimport com.evrencoskun.tableview.listener.scroll.VerticalRecyclerViewListener;\nimport com.evrencoskun.tableview.sort.SortState;\n\n/**\n * Created by evrencoskun on 19/06/2017.\n */\n\npublic interface ITableView {\n\n    void addView(View child, ViewGroup.LayoutParams params);\n\n    boolean hasFixedWidth();\n\n    boolean isIgnoreSelectionColors();\n\n    boolean isShowHorizontalSeparators();\n\n    boolean isShowVerticalSeparators();\n\n    boolean isAllowClickInsideCell();\n\n    boolean isSortable();\n\n    @NonNull\n    Context getContext();\n\n    @NonNull\n    CellRecyclerView getCellRecyclerView();\n\n    @NonNull\n    CellRecyclerView getColumnHeaderRecyclerView();\n\n    @NonNull\n    CellRecyclerView getRowHeaderRecyclerView();\n\n    @NonNull\n    ColumnHeaderLayoutManager getColumnHeaderLayoutManager();\n\n    @NonNull\n    CellLayoutManager getCellLayoutManager();\n\n    @NonNull\n    LinearLayoutManager getRowHeaderLayoutManager();\n\n    @NonNull\n    HorizontalRecyclerViewListener getHorizontalRecyclerViewListener();\n\n    @NonNull\n    VerticalRecyclerViewListener getVerticalRecyclerViewListener();\n\n    @Nullable\n    ITableViewListener getTableViewListener();\n\n    @NonNull\n    SelectionHandler getSelectionHandler();\n\n    @Nullable\n    ColumnSortHandler getColumnSortHandler();\n\n    @NonNull\n    VisibilityHandler getVisibilityHandler();\n\n    @NonNull\n    DividerItemDecoration getHorizontalItemDecoration();\n\n    @NonNull\n    DividerItemDecoration getVerticalItemDecoration();\n\n    @NonNull\n    SortState getSortingStatus(int column);\n\n    @Nullable\n    SortState getRowHeaderSortingStatus();\n\n    void scrollToColumnPosition(int column);\n\n    void scrollToColumnPosition(int column, int offset);\n\n    void scrollToRowPosition(int row);\n\n    void scrollToRowPosition(int row, int offset);\n\n    void showRow(int row);\n\n    void hideRow(int row);\n\n    boolean isRowVisible(int row);\n\n    void showAllHiddenRows();\n\n    void clearHiddenRowList();\n\n    void showColumn(int column);\n\n    void hideColumn(int column);\n\n    boolean isColumnVisible(int column);\n\n    void showAllHiddenColumns();\n\n    void clearHiddenColumnList();\n\n    int getShadowColor();\n\n    int getSelectedColor();\n\n    int getUnSelectedColor();\n\n    int getSeparatorColor();\n\n    void sortColumn(int columnPosition, @NonNull SortState sortState);\n\n    void sortRowHeader(@NonNull SortState sortState);\n\n    void remeasureColumnWidth(int column);\n\n    int getRowHeaderWidth();\n\n    void setRowHeaderWidth(int rowHeaderWidth);\n\n    boolean getShowCornerView();\n\n    enum CornerViewLocation {\n        TOP_LEFT(0),\n        TOP_RIGHT(1),\n        BOTTOM_LEFT(2),\n        BOTTOM_RIGHT(3);\n        int id;\n\n        CornerViewLocation(int id) {\n            this.id = id;\n        }\n\n        static CornerViewLocation fromId(int id) {\n            for (CornerViewLocation c : values()) {\n                if (c.id == id) return c;\n            }\n            // If enum not found return default of Top Left\n            return TOP_LEFT;\n        }\n    }\n\n    CornerViewLocation getCornerViewLocation();\n\n    void setCornerViewLocation(CornerViewLocation cornerViewLocation);\n\n    int getGravity();\n\n    boolean getReverseLayout();\n\n    void setReverseLayout(boolean reverseLayout);\n\n    @Nullable\n    AbstractTableAdapter getAdapter();\n\n    /**\n     * Filters the whole table using the provided Filter object which supports multiple filters.\n     *\n     * @param filter The filter object.\n     */\n    void filter(@NonNull Filter filter);\n\n    /**\n     * Retrieves the FilterHandler of the TableView.\n     *\n     * @return The FilterHandler of the TableView.\n     */\n    @Nullable\n    FilterHandler getFilterHandler();\n\n    /**\n     * Retrieves the ScrollHandler of the TableView.\n     *\n     * @return The ScrollHandler of the TableView.\n     */\n    @NonNull\n    ScrollHandler getScrollHandler();\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/TableView.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.PorterDuff;\nimport android.graphics.drawable.Drawable;\nimport android.os.Parcelable;\nimport android.util.AttributeSet;\nimport android.view.Gravity;\nimport android.view.ViewGroup;\nimport android.widget.FrameLayout;\n\nimport com.evrencoskun.tableview.adapter.AbstractTableAdapter;\nimport com.evrencoskun.tableview.adapter.recyclerview.CellRecyclerView;\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder;\nimport com.evrencoskun.tableview.filter.Filter;\nimport com.evrencoskun.tableview.handler.ColumnSortHandler;\nimport com.evrencoskun.tableview.handler.ColumnWidthHandler;\nimport com.evrencoskun.tableview.handler.FilterHandler;\nimport com.evrencoskun.tableview.handler.PreferencesHandler;\nimport com.evrencoskun.tableview.handler.ScrollHandler;\nimport com.evrencoskun.tableview.handler.SelectionHandler;\nimport com.evrencoskun.tableview.handler.VisibilityHandler;\nimport com.evrencoskun.tableview.layoutmanager.CellLayoutManager;\nimport com.evrencoskun.tableview.layoutmanager.ColumnHeaderLayoutManager;\nimport com.evrencoskun.tableview.listener.ITableViewListener;\nimport com.evrencoskun.tableview.listener.TableViewLayoutChangeListener;\nimport com.evrencoskun.tableview.listener.itemclick.ColumnHeaderRecyclerViewItemClickListener;\nimport com.evrencoskun.tableview.listener.itemclick.RowHeaderRecyclerViewItemClickListener;\nimport com.evrencoskun.tableview.listener.scroll.HorizontalRecyclerViewListener;\nimport com.evrencoskun.tableview.listener.scroll.VerticalRecyclerViewListener;\nimport com.evrencoskun.tableview.preference.SavedState;\nimport com.evrencoskun.tableview.sort.SortState;\n\nimport androidx.annotation.AttrRes;\nimport androidx.annotation.ColorInt;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.content.ContextCompat;\nimport androidx.recyclerview.widget.DividerItemDecoration;\nimport androidx.recyclerview.widget.LinearLayoutManager;\n\n/**\n * Created by evrencoskun on 11/06/2017.\n */\n\npublic class TableView extends FrameLayout implements ITableView {\n    @NonNull\n    protected CellRecyclerView mCellRecyclerView;\n    @NonNull\n    protected CellRecyclerView mColumnHeaderRecyclerView;\n    @NonNull\n    protected CellRecyclerView mRowHeaderRecyclerView;\n    @Nullable\n    protected AbstractTableAdapter mTableAdapter;\n    @Nullable\n    private ITableViewListener mTableViewListener;\n    @NonNull\n    private VerticalRecyclerViewListener mVerticalRecyclerListener;\n    @NonNull\n    private HorizontalRecyclerViewListener mHorizontalRecyclerViewListener;\n    @NonNull\n    private ColumnHeaderLayoutManager mColumnHeaderLayoutManager;\n    @NonNull\n    private LinearLayoutManager mRowHeaderLayoutManager;\n    @NonNull\n    private CellLayoutManager mCellLayoutManager;\n    @NonNull\n    private DividerItemDecoration mVerticalItemDecoration;\n    @NonNull\n    private DividerItemDecoration mHorizontalItemDecoration;\n    @NonNull\n    private SelectionHandler mSelectionHandler;\n    @Nullable\n    private ColumnSortHandler mColumnSortHandler;\n    @NonNull\n    private VisibilityHandler mVisibilityHandler;\n    @NonNull\n    private ScrollHandler mScrollHandler;\n    @Nullable\n    private FilterHandler mFilterHandler;\n    @NonNull\n    private PreferencesHandler mPreferencesHandler;\n    @NonNull\n    private ColumnWidthHandler mColumnWidthHandler;\n\n    private int mRowHeaderWidth;\n    private int mColumnHeaderHeight;\n\n    private int mSelectedColor;\n    private int mUnSelectedColor;\n    private int mShadowColor;\n    private int mSeparatorColor = -1;\n\n    private boolean mHasFixedWidth;\n    private boolean mIgnoreSelectionColors;\n    private boolean mShowHorizontalSeparators = true;\n    private boolean mShowVerticalSeparators = true;\n    private boolean mAllowClickInsideCell = false;\n    private boolean mAllowClickInsideRowHeader = false;\n    private boolean mAllowClickInsideColumnHeader = false;\n    private boolean mIsSortable;\n    private boolean mShowCornerView = false;\n\n    private CornerViewLocation mCornerViewLocation;\n\n    private boolean mReverseLayout = false;\n\n    public TableView(@NonNull Context context) {\n        super(context);\n        initialDefaultValues(null);\n        initialize();\n    }\n\n    public TableView(@NonNull Context context, @Nullable AttributeSet attrs) {\n        super(context, attrs);\n        initialDefaultValues(attrs);\n        initialize();\n    }\n\n    public TableView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int\n            defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        initialDefaultValues(null);\n        initialize();\n    }\n\n    /**\n     * Two Part class construction<br>\n     * Allows you to set various properties before class initialization if {@code intialize = false}<br>\n     * Allowing more control when programmically creating the class\n     *\n     * @param context\n     * @param initialize {@code false} to not call second part of class construction\n     *\n     * <p><b>Note:</b> If initialize is false you need to call {@code initilize()} method yourself.\n     *\n     */\n    public TableView(@NonNull Context context, boolean initialize) {\n        super(context);\n        initialDefaultValues(null);\n        if (initialize) initialize();\n    }\n\n    private void initialDefaultValues(@Nullable AttributeSet attrs) {\n        // Dimensions\n        mRowHeaderWidth = (int) getResources().getDimension(R.dimen.default_row_header_width);\n        mColumnHeaderHeight = (int) getResources().getDimension(R.dimen\n                .default_column_header_height);\n\n        // Cornerview location\n        mCornerViewLocation = ITableView.CornerViewLocation.TOP_LEFT;\n\n        // Reverse Layout\n        mReverseLayout = false;\n\n        // Colors\n        mSelectedColor = ContextCompat.getColor(getContext(), R.color\n                .table_view_default_selected_background_color);\n        mUnSelectedColor = ContextCompat.getColor(getContext(), R.color\n                .table_view_default_unselected_background_color);\n        mShadowColor = ContextCompat.getColor(getContext(), R.color\n                .table_view_default_shadow_background_color);\n\n        if (attrs == null) {\n            // That means TableView is created programmatically.\n            return;\n        }\n\n        // Get values from xml attributes\n        TypedArray a = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable\n                .TableView, 0, 0);\n        try {\n            // Dimensions\n            mRowHeaderWidth = (int) a.getDimension(R.styleable.TableView_row_header_width,\n                    mRowHeaderWidth);\n            mColumnHeaderHeight = (int) a.getDimension(R.styleable\n                    .TableView_column_header_height, mColumnHeaderHeight);\n\n            // CornerView location\n            mCornerViewLocation = CornerViewLocation.fromId(a.getInt(R.styleable.TableView_corner_view_location, 0));\n\n            // Reverse Layout\n            mReverseLayout = a.getBoolean(R.styleable.TableView_reverse_layout, mReverseLayout);\n\n            // Colors\n            mSelectedColor = a.getColor(R.styleable.TableView_selected_color, mSelectedColor);\n            mUnSelectedColor = a.getColor(R.styleable.TableView_unselected_color, mUnSelectedColor);\n            mShadowColor = a.getColor(R.styleable.TableView_shadow_color, mShadowColor);\n            mSeparatorColor = a.getColor(R.styleable.TableView_separator_color, ContextCompat\n                    .getColor(getContext(), R.color.table_view_default_separator_color));\n\n            // Booleans\n            mShowVerticalSeparators = a.getBoolean(R.styleable.TableView_show_vertical_separator,\n                    mShowVerticalSeparators);\n            mShowHorizontalSeparators = a.getBoolean(R.styleable\n                    .TableView_show_horizontal_separator, mShowHorizontalSeparators);\n            mAllowClickInsideCell = a.getBoolean(R.styleable.TableView_allow_click_inside_cell,\n                    mAllowClickInsideCell);\n            mAllowClickInsideRowHeader = a.getBoolean(R.styleable.TableView_allow_click_inside_row_header,\n                    mAllowClickInsideRowHeader);\n            mAllowClickInsideColumnHeader = a.getBoolean(R.styleable.TableView_allow_click_inside_column_header,\n                    mAllowClickInsideColumnHeader);\n\n        } finally {\n            a.recycle();\n        }\n    }\n\n    /**\n     * Second Part of class construction\n     *\n     * <p><b>Note:</b> This should only be called directly if the class was constructed\n     * with initialize boolean set to {@code false}\n     */\n    public void initialize() {\n\n        // Create Views\n        mColumnHeaderRecyclerView = createColumnHeaderRecyclerView();\n        mRowHeaderRecyclerView = createRowHeaderRecyclerView();\n        mCellRecyclerView = createCellRecyclerView();\n\n        // Set some Id to help in identification\n        mColumnHeaderRecyclerView.setId(R.id.ColumnHeaderRecyclerView);\n        mRowHeaderRecyclerView.setId(R.id.RowHeaderRecyclerView);\n        mCellRecyclerView.setId(R.id.CellRecyclerView);\n\n        // Add Views\n        addView(mColumnHeaderRecyclerView);\n        addView(mRowHeaderRecyclerView);\n        addView(mCellRecyclerView);\n\n        // Create Handlers\n        mSelectionHandler = new SelectionHandler(this);\n        mVisibilityHandler = new VisibilityHandler(this);\n        mScrollHandler = new ScrollHandler(this);\n        mPreferencesHandler = new PreferencesHandler(this);\n        mColumnWidthHandler = new ColumnWidthHandler(this);\n\n        initializeListeners();\n    }\n\n    protected void initializeListeners() {\n\n        // --- Listeners to help Scroll synchronously ---\n        // It handles Vertical scroll listener\n        mVerticalRecyclerListener = new VerticalRecyclerViewListener(this);\n\n        // Set this listener both of Cell RecyclerView and RowHeader RecyclerView\n        mRowHeaderRecyclerView.addOnItemTouchListener(mVerticalRecyclerListener);\n        mCellRecyclerView.addOnItemTouchListener(mVerticalRecyclerListener);\n\n        // It handles Horizontal scroll listener\n        mHorizontalRecyclerViewListener = new HorizontalRecyclerViewListener(this);\n        // Set scroll listener to be able to scroll all rows synchrony.\n        mColumnHeaderRecyclerView.addOnItemTouchListener(mHorizontalRecyclerViewListener);\n\n\n        // --- Listeners to help item clicks ---\n        // Create item click listeners\n\n        // Add item click listener for column header recyclerView\n        if (mAllowClickInsideColumnHeader) {\n            ColumnHeaderRecyclerViewItemClickListener columnHeaderRecyclerViewItemClickListener = new ColumnHeaderRecyclerViewItemClickListener\n                    (mColumnHeaderRecyclerView, this);\n            mColumnHeaderRecyclerView.addOnItemTouchListener(columnHeaderRecyclerViewItemClickListener);\n        }\n\n        // Add item click listener for row header recyclerView\n        if (mAllowClickInsideRowHeader) {\n            RowHeaderRecyclerViewItemClickListener rowHeaderRecyclerViewItemClickListener = new RowHeaderRecyclerViewItemClickListener\n                    (mRowHeaderRecyclerView, this);\n            mRowHeaderRecyclerView.addOnItemTouchListener(rowHeaderRecyclerViewItemClickListener);\n        }\n\n\n        // Add Layout change listener both of Column Header  & Cell recyclerView to detect\n        // changing size\n        // For some case, it is pretty necessary.\n        TableViewLayoutChangeListener layoutChangeListener = new TableViewLayoutChangeListener\n                (this);\n        mColumnHeaderRecyclerView.addOnLayoutChangeListener(layoutChangeListener);\n        mCellRecyclerView.addOnLayoutChangeListener(layoutChangeListener);\n\n    }\n\n    @NonNull\n    protected CellRecyclerView createColumnHeaderRecyclerView() {\n        CellRecyclerView recyclerView = new CellRecyclerView(getContext());\n\n        // Set layout manager\n        recyclerView.setLayoutManager(getColumnHeaderLayoutManager());\n\n        // Set layout params\n        LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,\n                mColumnHeaderHeight, getGravity());\n        // If the corner is on the right the margin needs to be on the right\n        if (mCornerViewLocation == CornerViewLocation.TOP_RIGHT || mCornerViewLocation == CornerViewLocation.BOTTOM_RIGHT) {\n            layoutParams.rightMargin = mRowHeaderWidth;\n        } else {\n            layoutParams.leftMargin = mRowHeaderWidth;\n        }\n\n        recyclerView.setLayoutParams(layoutParams);\n\n        if (isShowHorizontalSeparators()) {\n            // Add vertical item decoration to display column line\n            recyclerView.addItemDecoration(getHorizontalItemDecoration());\n        }\n\n        return recyclerView;\n    }\n\n    @NonNull\n    protected CellRecyclerView createRowHeaderRecyclerView() {\n        CellRecyclerView recyclerView = new CellRecyclerView(getContext());\n\n        // Set layout manager\n        recyclerView.setLayoutManager(getRowHeaderLayoutManager());\n\n        // Set layout params\n        LayoutParams layoutParams = new LayoutParams(mRowHeaderWidth, LayoutParams.WRAP_CONTENT, getGravity());\n        // If the corner is on the bottom the margin needs to be on the bottom\n        if (mCornerViewLocation == CornerViewLocation.BOTTOM_LEFT || mCornerViewLocation == CornerViewLocation.BOTTOM_RIGHT) {\n            layoutParams.bottomMargin = mColumnHeaderHeight;\n        } else {\n            layoutParams.topMargin = mColumnHeaderHeight;\n        }\n        recyclerView.setLayoutParams(layoutParams);\n\n\n        if (isShowVerticalSeparators()) {\n            // Add vertical item decoration to display row line\n            recyclerView.addItemDecoration(getVerticalItemDecoration());\n        }\n\n        return recyclerView;\n    }\n\n    @NonNull\n    protected CellRecyclerView createCellRecyclerView() {\n        CellRecyclerView recyclerView = new CellRecyclerView(getContext());\n\n        // Disable multitouch\n        recyclerView.setMotionEventSplittingEnabled(false);\n\n        // Set layout manager\n        recyclerView.setLayoutManager(getCellLayoutManager());\n\n        // Set layout params\n        LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams\n                .WRAP_CONTENT, getGravity());\n        // If the corner is on the right the margin needs to be on the right\n        if (mCornerViewLocation == CornerViewLocation.TOP_RIGHT || mCornerViewLocation == CornerViewLocation.BOTTOM_RIGHT) {\n            layoutParams.rightMargin = mRowHeaderWidth;\n        } else {\n            layoutParams.leftMargin = mRowHeaderWidth;\n        }\n        // If the corner is on the bottom the margin needs to be on the bottom\n        if (mCornerViewLocation == CornerViewLocation.BOTTOM_LEFT || mCornerViewLocation == CornerViewLocation.BOTTOM_RIGHT) {\n            layoutParams.bottomMargin = mColumnHeaderHeight;\n        } else {\n            layoutParams.topMargin = mColumnHeaderHeight;\n        }\n        recyclerView.setLayoutParams(layoutParams);\n\n        if (isShowVerticalSeparators()) {\n            // Add vertical item decoration to display row line on center recycler view\n            recyclerView.addItemDecoration(getVerticalItemDecoration());\n        }\n\n        return recyclerView;\n    }\n\n    public <CH, RH, C> void setAdapter(@Nullable AbstractTableAdapter<CH, RH, C> tableAdapter) {\n        if (tableAdapter != null) {\n            this.mTableAdapter = tableAdapter;\n            this.mTableAdapter.setRowHeaderWidth(mRowHeaderWidth);\n            this.mTableAdapter.setColumnHeaderHeight(mColumnHeaderHeight);\n            this.mTableAdapter.setTableView(this);\n\n            // set adapters\n            mColumnHeaderRecyclerView.setAdapter(mTableAdapter.getColumnHeaderRecyclerViewAdapter());\n            mRowHeaderRecyclerView.setAdapter(mTableAdapter.getRowHeaderRecyclerViewAdapter());\n            mCellRecyclerView.setAdapter(mTableAdapter.getCellRecyclerViewAdapter());\n\n            // Create Sort Handler\n            mColumnSortHandler = new ColumnSortHandler(this);\n\n            // Create Filter Handler\n            mFilterHandler = new FilterHandler<>(this);\n        }\n    }\n\n    @Override\n    public boolean hasFixedWidth() {\n        return mHasFixedWidth;\n    }\n\n    public void setHasFixedWidth(boolean hasFixedWidth) {\n        this.mHasFixedWidth = hasFixedWidth;\n\n        // RecyclerView has also the same control to provide better performance.\n        mColumnHeaderRecyclerView.setHasFixedSize(hasFixedWidth);\n    }\n\n    @Override\n    public boolean isIgnoreSelectionColors() {\n        return mIgnoreSelectionColors;\n    }\n\n    public void setIgnoreSelectionColors(boolean ignoreSelectionColor) {\n        this.mIgnoreSelectionColors = ignoreSelectionColor;\n    }\n\n    @Override\n    public boolean isShowHorizontalSeparators() {\n        return mShowHorizontalSeparators;\n    }\n\n    @Override\n    public boolean isAllowClickInsideCell(){\n        return mAllowClickInsideCell;\n    }\n\n    @Override\n    public boolean isSortable() {\n        return mIsSortable;\n    }\n\n    public void setShowHorizontalSeparators(boolean showSeparators) {\n        this.mShowHorizontalSeparators = showSeparators;\n    }\n\n    @Override\n    public boolean isShowVerticalSeparators() {\n        return mShowVerticalSeparators;\n    }\n\n    public void setShowVerticalSeparators(boolean showSeparators) {\n        this.mShowVerticalSeparators = showSeparators;\n    }\n\n    @NonNull\n    @Override\n    public CellRecyclerView getCellRecyclerView() {\n        return mCellRecyclerView;\n    }\n\n    @NonNull\n    @Override\n    public CellRecyclerView getColumnHeaderRecyclerView() {\n        return mColumnHeaderRecyclerView;\n    }\n\n    @NonNull\n    @Override\n    public CellRecyclerView getRowHeaderRecyclerView() {\n        return mRowHeaderRecyclerView;\n    }\n\n    @NonNull\n    @Override\n    public ColumnHeaderLayoutManager getColumnHeaderLayoutManager() {\n        if (mColumnHeaderLayoutManager == null) {\n            mColumnHeaderLayoutManager = new ColumnHeaderLayoutManager(getContext(), this);\n            if (mReverseLayout) mColumnHeaderLayoutManager.setReverseLayout(true);\n        }\n        return mColumnHeaderLayoutManager;\n    }\n\n    @NonNull\n    @Override\n    public CellLayoutManager getCellLayoutManager() {\n        if (mCellLayoutManager == null) {\n            mCellLayoutManager = new CellLayoutManager(getContext(), this);\n        }\n        return mCellLayoutManager;\n    }\n\n    @NonNull\n    @Override\n    public LinearLayoutManager getRowHeaderLayoutManager() {\n        if (mRowHeaderLayoutManager == null) {\n            mRowHeaderLayoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager\n                    .VERTICAL, false);\n        }\n        return mRowHeaderLayoutManager;\n    }\n\n    @NonNull\n    @Override\n    public HorizontalRecyclerViewListener getHorizontalRecyclerViewListener() {\n        return mHorizontalRecyclerViewListener;\n    }\n\n    @NonNull\n    @Override\n    public VerticalRecyclerViewListener getVerticalRecyclerViewListener() {\n        return mVerticalRecyclerListener;\n    }\n\n    @Nullable\n    @Override\n    public ITableViewListener getTableViewListener() {\n        return mTableViewListener;\n    }\n\n    public void setTableViewListener(@Nullable ITableViewListener tableViewListener) {\n        this.mTableViewListener = tableViewListener;\n    }\n\n    @Override\n    public void sortColumn(int columnPosition, @NonNull SortState sortState) {\n        mIsSortable = true;\n        mColumnSortHandler.sort(columnPosition, sortState);\n    }\n\n    @Override\n    public void sortRowHeader(@NonNull SortState sortState) {\n        mIsSortable = true;\n        mColumnSortHandler.sortByRowHeader(sortState);\n    }\n\n    @Override\n    public void remeasureColumnWidth(int column) {\n        // Remove calculated width value to be ready for recalculation.\n        getColumnHeaderLayoutManager().removeCachedWidth(column);\n        // Recalculate of the width values of the columns\n        getCellLayoutManager().fitWidthSize(column, false);\n    }\n\n    @Nullable\n    @Override\n    public AbstractTableAdapter getAdapter() {\n        return mTableAdapter;\n    }\n\n    @Override\n    public void filter(@NonNull Filter filter) {\n        mFilterHandler.filter(filter);\n    }\n\n    @Nullable\n    @Override\n    public FilterHandler getFilterHandler() {\n        return mFilterHandler;\n    }\n\n    @NonNull\n    @Override\n    public SortState getSortingStatus(int column) {\n        return mColumnSortHandler.getSortingStatus(column);\n    }\n\n    @Nullable\n    @Override\n    public SortState getRowHeaderSortingStatus() {\n        return mColumnSortHandler.getRowHeaderSortingStatus();\n    }\n\n    @Override\n    public void scrollToColumnPosition(int column) {\n        mScrollHandler.scrollToColumnPosition(column);\n    }\n\n    @Override\n    public void scrollToColumnPosition(int column, int offset) {\n        mScrollHandler.scrollToColumnPosition(column, offset);\n    }\n\n    @Override\n    public void scrollToRowPosition(int row) {\n        mScrollHandler.scrollToRowPosition(row);\n    }\n\n    @Override\n    public void scrollToRowPosition(int row, int offset) {\n        mScrollHandler.scrollToRowPosition(row, offset);\n    }\n\n    @NonNull\n    public ScrollHandler getScrollHandler() {\n        return mScrollHandler;\n    }\n\n    @Override\n    public void showRow(int row) {\n        mVisibilityHandler.showRow(row);\n    }\n\n    @Override\n    public void hideRow(int row) {\n        mVisibilityHandler.hideRow(row);\n    }\n\n    @Override\n    public void showAllHiddenRows() {\n        mVisibilityHandler.showAllHiddenRows();\n    }\n\n    @Override\n    public void clearHiddenRowList() {\n        mVisibilityHandler.clearHideRowList();\n    }\n\n    @Override\n    public void showColumn(int column) {\n        mVisibilityHandler.showColumn(column);\n    }\n\n    @Override\n    public void hideColumn(int column) {\n        mVisibilityHandler.hideColumn(column);\n    }\n\n    @Override\n    public boolean isColumnVisible(int column) {\n        return mVisibilityHandler.isColumnVisible(column);\n    }\n\n    @Override\n    public void showAllHiddenColumns() {\n        mVisibilityHandler.showAllHiddenColumns();\n    }\n\n    @Override\n    public void clearHiddenColumnList() {\n        mVisibilityHandler.clearHideColumnList();\n    }\n\n    @Override\n    public boolean isRowVisible(int row) {\n        return mVisibilityHandler.isRowVisible(row);\n    }\n\n    /**\n     * Returns the index of the selected row, -1 if no row is selected.\n     */\n    public int getSelectedRow() {\n        return mSelectionHandler.getSelectedRowPosition();\n    }\n\n    public void setSelectedRow(int row) {\n        // Find the row header view holder which is located on row position.\n        AbstractViewHolder rowViewHolder = (AbstractViewHolder) getRowHeaderRecyclerView()\n                .findViewHolderForAdapterPosition(row);\n\n\n        mSelectionHandler.setSelectedRowPosition(rowViewHolder, row);\n    }\n\n    /**\n     * Returns the index of the selected column, -1 if no column is selected.\n     */\n    public int getSelectedColumn() {\n        return mSelectionHandler.getSelectedColumnPosition();\n    }\n\n    public void setSelectedColumn(int column) {\n        // Find the column view holder which is located on column position .\n        AbstractViewHolder columnViewHolder = (AbstractViewHolder) getColumnHeaderRecyclerView()\n                .findViewHolderForAdapterPosition(column);\n\n        mSelectionHandler.setSelectedColumnPosition(columnViewHolder, column);\n    }\n\n    public void setSelectedCell(int column, int row) {\n        // Find the cell view holder which is located on x,y (column,row) position.\n        AbstractViewHolder cellViewHolder = getCellLayoutManager().getCellViewHolder(column, row);\n\n        mSelectionHandler.setSelectedCellPositions(cellViewHolder, column, row);\n    }\n\n    @NonNull\n    @Override\n    public SelectionHandler getSelectionHandler() {\n        return mSelectionHandler;\n    }\n\n    @Nullable\n    @Override\n    public ColumnSortHandler getColumnSortHandler() {\n        return mColumnSortHandler;\n    }\n\n    @NonNull\n    @Override\n    public VisibilityHandler getVisibilityHandler() {\n        return mVisibilityHandler;\n    }\n\n    @NonNull\n    @Override\n    public DividerItemDecoration getHorizontalItemDecoration() {\n        if (mHorizontalItemDecoration == null) {\n            mHorizontalItemDecoration = createItemDecoration(DividerItemDecoration.HORIZONTAL);\n        }\n        return mHorizontalItemDecoration;\n    }\n\n    @NonNull\n    @Override\n    public DividerItemDecoration getVerticalItemDecoration() {\n        if (mVerticalItemDecoration == null) {\n            mVerticalItemDecoration = createItemDecoration(DividerItemDecoration.VERTICAL);\n        }\n        return mVerticalItemDecoration;\n    }\n\n    @NonNull\n    protected DividerItemDecoration createItemDecoration(int orientation) {\n        DividerItemDecoration itemDecoration = new DividerItemDecoration(getContext(), orientation);\n        Drawable divider = ContextCompat.getDrawable(getContext(), R.drawable.cell_line_divider);\n        if (divider == null) {\n            return itemDecoration;\n        }\n\n        // That means; There is a custom separator color from user.\n        if (mSeparatorColor != -1) {\n            // Change its color\n            divider.setColorFilter(mSeparatorColor, PorterDuff.Mode.SRC_ATOP);\n        }\n\n        itemDecoration.setDrawable(divider);\n        return itemDecoration;\n    }\n\n    /**\n     * This method helps to change default selected color programmatically.\n     *\n     * @param selectedColor It must be Color int.\n     */\n    public void setSelectedColor(@ColorInt int selectedColor) {\n        this.mSelectedColor = selectedColor;\n    }\n\n    @ColorInt\n    @Override\n    public int getSelectedColor() {\n        return mSelectedColor;\n    }\n\n    public void setSeparatorColor(@ColorInt int mSeparatorColor) {\n        this.mSeparatorColor = mSeparatorColor;\n    }\n\n    @ColorInt\n    @Override\n    public int getSeparatorColor() {\n        return mSeparatorColor;\n    }\n\n    /**\n     * This method helps to change default unselected color programmatically.\n     *\n     * @param unSelectedColor It must be Color int.\n     */\n    public void setUnSelectedColor(@ColorInt int unSelectedColor) {\n        this.mUnSelectedColor = unSelectedColor;\n    }\n\n    @ColorInt\n    @Override\n    public int getUnSelectedColor() {\n        return mUnSelectedColor;\n    }\n\n    public void setShadowColor(@ColorInt int shadowColor) {\n        this.mShadowColor = shadowColor;\n    }\n\n    @Override\n    public @ColorInt\n    int getShadowColor() {\n        return mShadowColor;\n    }\n\n    /**\n     * get row header width\n     *\n     * @return size in pixel\n     */\n    @Override\n    public int getRowHeaderWidth() {\n        return mRowHeaderWidth;\n    }\n\n    /**\n     * set RowHeaderWidth\n     *\n     * @param rowHeaderWidth in pixel\n     */\n    @Override\n    public void setRowHeaderWidth(int rowHeaderWidth) {\n        this.mRowHeaderWidth = rowHeaderWidth;\n\n        // Update RowHeader layout width\n        ViewGroup.LayoutParams layoutParamsRow = mRowHeaderRecyclerView.getLayoutParams();\n        layoutParamsRow.width = rowHeaderWidth;\n        mRowHeaderRecyclerView.setLayoutParams(layoutParamsRow);\n        mRowHeaderRecyclerView.requestLayout();\n\n        // Update ColumnHeader left margin\n        LayoutParams layoutParamsColumn = (LayoutParams) mColumnHeaderRecyclerView.getLayoutParams();\n        // If the corner is on the right the margin needs to be on the right\n        if (mCornerViewLocation == CornerViewLocation.TOP_RIGHT || mCornerViewLocation == CornerViewLocation.BOTTOM_RIGHT) {\n            layoutParamsColumn.rightMargin = rowHeaderWidth;\n        } else {\n            layoutParamsColumn.leftMargin = rowHeaderWidth;\n        }\n        mColumnHeaderRecyclerView.setLayoutParams(layoutParamsColumn);\n        mColumnHeaderRecyclerView.requestLayout();\n\n        // Update Cells left margin\n        LayoutParams layoutParamsCell = (LayoutParams) mCellRecyclerView.getLayoutParams();\n        if (mCornerViewLocation == CornerViewLocation.TOP_RIGHT || mCornerViewLocation == CornerViewLocation.BOTTOM_RIGHT) {\n            layoutParamsCell.rightMargin = rowHeaderWidth;\n        } else {\n            layoutParamsCell.leftMargin = rowHeaderWidth;\n        }\n        mCellRecyclerView.setLayoutParams(layoutParamsCell);\n        mCellRecyclerView.requestLayout();\n\n        if (getAdapter() != null) {\n            // update CornerView size\n            getAdapter().setRowHeaderWidth(rowHeaderWidth);\n        }\n    }\n\n    public void setColumnWidth(int columnPosition, int width) {\n        mColumnWidthHandler.setColumnWidth(columnPosition, width);\n    }\n\n    public void setShowCornerView(boolean showCornerView){\n        mShowCornerView = showCornerView;\n    }\n\n    public boolean getShowCornerView(){\n        return mShowCornerView;\n    }\n\n    public CornerViewLocation getCornerViewLocation() { return mCornerViewLocation; }\n\n    @Override\n    public void setCornerViewLocation(CornerViewLocation cornerViewLocation) {\n        mCornerViewLocation = cornerViewLocation;\n    }\n\n    public int getGravity() {\n        int gravity;\n        switch (mCornerViewLocation) {\n            case TOP_LEFT:\n                gravity = Gravity.TOP|Gravity.LEFT;\n                break;\n            case TOP_RIGHT:\n                gravity = Gravity.TOP|Gravity.RIGHT;\n                break;\n            case BOTTOM_LEFT:\n                gravity = Gravity.BOTTOM|Gravity.LEFT;\n                break;\n            case BOTTOM_RIGHT:\n                gravity = Gravity.BOTTOM|Gravity.RIGHT;\n                break;\n            default:\n                gravity = Gravity.TOP|Gravity.LEFT;\n                break;\n        }\n        return gravity;\n    }\n\n    public boolean getReverseLayout(){ return mReverseLayout;}\n\n    public void setReverseLayout(boolean reverseLayout) {\n        mReverseLayout = reverseLayout;\n    }\n\n    @Nullable\n    @Override\n    protected Parcelable onSaveInstanceState() {\n        SavedState state = new SavedState(super.onSaveInstanceState());\n        // Save all preferences of The TableView before the configuration changed.\n        state.preferences = mPreferencesHandler.savePreferences();\n        return state;\n    }\n\n    @Override\n    protected void onRestoreInstanceState(Parcelable state) {\n\n        if (!(state instanceof SavedState)) {\n            super.onRestoreInstanceState(state);\n            return;\n        }\n\n        SavedState savedState = (SavedState) state;\n        super.onRestoreInstanceState(savedState.getSuperState());\n\n        // Reload the preferences\n        mPreferencesHandler.loadPreferences(savedState.preferences);\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/adapter/AbstractTableAdapter.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.adapter;\n\nimport android.content.Context;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.FrameLayout;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.evrencoskun.tableview.ITableView;\nimport com.evrencoskun.tableview.adapter.recyclerview.CellRecyclerViewAdapter;\nimport com.evrencoskun.tableview.adapter.recyclerview.ColumnHeaderRecyclerViewAdapter;\nimport com.evrencoskun.tableview.adapter.recyclerview.RowHeaderRecyclerViewAdapter;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Created by evrencoskun on 10/06/2017.\n */\n\npublic abstract class AbstractTableAdapter<CH, RH, C> implements ITableAdapter<CH, RH, C> {\n\n    private int mRowHeaderWidth;\n    private int mColumnHeaderHeight;\n\n    private ColumnHeaderRecyclerViewAdapter<CH> mColumnHeaderRecyclerViewAdapter;\n    private RowHeaderRecyclerViewAdapter<RH> mRowHeaderRecyclerViewAdapter;\n    private CellRecyclerViewAdapter mCellRecyclerViewAdapter;\n    private View mCornerView;\n\n    protected List<CH> mColumnHeaderItems;\n    protected List<RH> mRowHeaderItems;\n    protected List<List<C>> mCellItems;\n\n    private ITableView mTableView;\n    private List<AdapterDataSetChangedListener<CH, RH, C>> dataSetChangedListeners;\n\n    public void setTableView(@NonNull ITableView tableView) {\n        mTableView = tableView;\n        initialize();\n    }\n\n    private void initialize() {\n        Context context = mTableView.getContext();\n\n        // Create Column header RecyclerView Adapter\n        mColumnHeaderRecyclerViewAdapter = new ColumnHeaderRecyclerViewAdapter<>(context,\n                mColumnHeaderItems, this);\n\n        // Create Row Header RecyclerView Adapter\n        mRowHeaderRecyclerViewAdapter = new RowHeaderRecyclerViewAdapter<>(context,\n                mRowHeaderItems, this);\n\n        // Create Cell RecyclerView Adapter\n        mCellRecyclerViewAdapter = new CellRecyclerViewAdapter<>(context, mCellItems, mTableView);\n    }\n\n    public void setColumnHeaderItems(@Nullable List<CH> columnHeaderItems) {\n        if (columnHeaderItems == null) {\n            return;\n        }\n\n        mColumnHeaderItems = columnHeaderItems;\n        // Invalidate the cached widths for letting the view measure the cells width\n        // from scratch.\n        mTableView.getColumnHeaderLayoutManager().clearCachedWidths();\n        // Set the items to the adapter\n        mColumnHeaderRecyclerViewAdapter.setItems(mColumnHeaderItems);\n        dispatchColumnHeaderDataSetChangesToListeners(columnHeaderItems);\n    }\n\n    public void setRowHeaderItems(@Nullable List<RH> rowHeaderItems) {\n        if (rowHeaderItems == null) {\n            return;\n        }\n\n        mRowHeaderItems = rowHeaderItems;\n\n        // Set the items to the adapter\n        mRowHeaderRecyclerViewAdapter.setItems(mRowHeaderItems);\n        dispatchRowHeaderDataSetChangesToListeners(mRowHeaderItems);\n    }\n\n    public void setCellItems(@Nullable List<List<C>> cellItems) {\n        if (cellItems == null) {\n            return;\n        }\n\n        mCellItems = cellItems;\n        // Invalidate the cached widths for letting the view measure the cells width\n        // from scratch.\n        mTableView.getCellLayoutManager().clearCachedWidths();\n        // Set the items to the adapter\n        mCellRecyclerViewAdapter.setItems(mCellItems);\n        dispatchCellDataSetChangesToListeners(mCellItems);\n    }\n\n    public void setAllItems(\n            @Nullable List<CH> columnHeaderItems,\n            @Nullable List<RH> rowHeaderItems,\n            @Nullable List<List<C>> cellItems\n    ) {\n        // Set all items\n        setColumnHeaderItems(columnHeaderItems);\n        setRowHeaderItems(rowHeaderItems);\n        setCellItems(cellItems);\n\n        // Control corner view\n        updateCornerViewState(columnHeaderItems, rowHeaderItems);\n    }\n\n    private void updateCornerViewState(\n            @Nullable List<CH> columnHeaderItems,\n            @Nullable List<RH> rowHeaderItems\n    ) {\n        boolean hasColumnHeaders = columnHeaderItems != null && !columnHeaderItems.isEmpty();\n        boolean hasRowHeaders = rowHeaderItems != null && !rowHeaderItems.isEmpty();\n        boolean showCornerView = mTableView != null && mTableView.getShowCornerView();\n        boolean needCornerSpace = hasColumnHeaders && (hasRowHeaders || showCornerView);\n\n        // Create the corner view if we need it\n        if (mCornerView == null && needCornerSpace) {\n            // No TableView is associated with this Adapter, so we can't create the corner view\n            if (mTableView == null) {\n                return;\n            }\n\n            FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(\n                    mRowHeaderWidth,\n                    mColumnHeaderHeight,\n                    mTableView.getGravity()\n            );\n\n            // Create corner view\n            mCornerView = onCreateCornerView((ViewGroup) mTableView);\n\n            // Set the corner location\n            mTableView.addView(mCornerView, layoutParams);\n        }\n\n        // We don't have any corner view to update\n        if (mCornerView == null) {\n            return;\n        }\n\n        if (needCornerSpace) {\n            mCornerView.setVisibility(View.VISIBLE);\n        } else {\n            mCornerView.setVisibility(View.GONE);\n        }\n    }\n\n    @Override\n    public int getColumnHeaderItemViewType(int position) {\n        return 0;\n    }\n\n    @Override\n    public int getRowHeaderItemViewType(int position) {\n        return 0;\n    }\n\n    @Override\n    public int getCellItemViewType(int position) {\n        return 0;\n    }\n\n    @Nullable\n    @Override\n    public View getCornerView() {\n        return mCornerView;\n    }\n\n    public ColumnHeaderRecyclerViewAdapter getColumnHeaderRecyclerViewAdapter() {\n        return mColumnHeaderRecyclerViewAdapter;\n    }\n\n    public RowHeaderRecyclerViewAdapter getRowHeaderRecyclerViewAdapter() {\n        return mRowHeaderRecyclerViewAdapter;\n    }\n\n    public CellRecyclerViewAdapter getCellRecyclerViewAdapter() {\n        return mCellRecyclerViewAdapter;\n    }\n\n    public void setRowHeaderWidth(int rowHeaderWidth) {\n        this.mRowHeaderWidth = rowHeaderWidth;\n\n        if (mCornerView != null) {\n            ViewGroup.LayoutParams layoutParams = mCornerView.getLayoutParams();\n            layoutParams.width = rowHeaderWidth;\n        }\n    }\n\n    public void setColumnHeaderHeight(int columnHeaderHeight) {\n        this.mColumnHeaderHeight = columnHeaderHeight;\n    }\n\n    @Nullable\n    public CH getColumnHeaderItem(int position) {\n        if ((mColumnHeaderItems == null || mColumnHeaderItems.isEmpty()) || position < 0 ||\n                position >= mColumnHeaderItems.size()) {\n            return null;\n        }\n        return mColumnHeaderItems.get(position);\n    }\n\n    @Nullable\n    public RH getRowHeaderItem(int position) {\n        if ((mRowHeaderItems == null || mRowHeaderItems.isEmpty()) || position < 0 || position >=\n                mRowHeaderItems.size()) {\n            return null;\n        }\n        return mRowHeaderItems.get(position);\n    }\n\n    @Nullable\n    public C getCellItem(int columnPosition, int rowPosition) {\n        if ((mCellItems == null || mCellItems.isEmpty()) || columnPosition < 0 || rowPosition >=\n                mCellItems.size() || mCellItems.get(rowPosition) == null || rowPosition < 0 ||\n                columnPosition >= mCellItems.get(rowPosition).size()) {\n            return null;\n        }\n\n        return mCellItems.get(rowPosition).get(columnPosition);\n    }\n\n    @Nullable\n    public List<C> getCellRowItems(int rowPosition) {\n        return (List<C>) mCellRecyclerViewAdapter.getItem(rowPosition);\n    }\n\n    public void removeRow(int rowPosition) {\n        mCellRecyclerViewAdapter.deleteItem(rowPosition);\n        mRowHeaderRecyclerViewAdapter.deleteItem(rowPosition);\n    }\n\n    public void removeRow(int rowPosition, boolean updateRowHeader) {\n        mCellRecyclerViewAdapter.deleteItem(rowPosition);\n\n        // To be able update the row header data\n        if (updateRowHeader) {\n            rowPosition = mRowHeaderRecyclerViewAdapter.getItemCount() - 1;\n\n            // Cell RecyclerView items should be notified.\n            // Because, other items stores the old row position.\n            mCellRecyclerViewAdapter.notifyDataSetChanged();\n        }\n\n        mRowHeaderRecyclerViewAdapter.deleteItem(rowPosition);\n\n    }\n\n    public void removeRowRange(int rowPositionStart, int itemCount) {\n        mCellRecyclerViewAdapter.deleteItemRange(rowPositionStart, itemCount);\n        mRowHeaderRecyclerViewAdapter.deleteItemRange(rowPositionStart, itemCount);\n    }\n\n    public void removeRowRange(int rowPositionStart, int itemCount, boolean updateRowHeader) {\n        mCellRecyclerViewAdapter.deleteItemRange(rowPositionStart, itemCount);\n\n        // To be able update the row header data sets\n        if (updateRowHeader) {\n            rowPositionStart = mRowHeaderRecyclerViewAdapter.getItemCount() - 1 - itemCount;\n\n            // Cell RecyclerView items should be notified.\n            // Because, other items stores the old row position.\n            mCellRecyclerViewAdapter.notifyDataSetChanged();\n        }\n\n        mRowHeaderRecyclerViewAdapter.deleteItemRange(rowPositionStart, itemCount);\n    }\n\n    public void addRow(int rowPosition, @Nullable RH rowHeaderItem, @Nullable List<C> cellItems) {\n        mCellRecyclerViewAdapter.addItem(rowPosition, cellItems);\n        mRowHeaderRecyclerViewAdapter.addItem(rowPosition, rowHeaderItem);\n    }\n\n    public void addRowRange(int rowPositionStart, @Nullable List<RH> rowHeaderItem, @Nullable List<List<C>> cellItems) {\n        mRowHeaderRecyclerViewAdapter.addItemRange(rowPositionStart, rowHeaderItem);\n        mCellRecyclerViewAdapter.addItemRange(rowPositionStart, cellItems);\n    }\n\n    public void changeRowHeaderItem(int rowPosition, @Nullable RH rowHeaderModel) {\n        mRowHeaderRecyclerViewAdapter.changeItem(rowPosition, rowHeaderModel);\n    }\n\n    public void changeRowHeaderItemRange(int rowPositionStart, @Nullable List<RH> rowHeaderModelList) {\n        mRowHeaderRecyclerViewAdapter.changeItemRange(rowPositionStart, rowHeaderModelList);\n    }\n\n    public void changeCellItem(int columnPosition, int rowPosition, C cellModel) {\n        List<C> cellItems = (List<C>) mCellRecyclerViewAdapter.getItem(rowPosition);\n        if (cellItems != null && cellItems.size() > columnPosition) {\n            // Update cell row items.\n            cellItems.set(columnPosition, cellModel);\n\n            mCellRecyclerViewAdapter.changeItem(rowPosition, cellItems);\n        }\n    }\n\n    public void changeColumnHeader(int columnPosition, @Nullable CH columnHeaderModel) {\n        mColumnHeaderRecyclerViewAdapter.changeItem(columnPosition, columnHeaderModel);\n    }\n\n    public void changeColumnHeaderRange(int columnPositionStart, @Nullable List<CH> columnHeaderModelList) {\n        mColumnHeaderRecyclerViewAdapter.changeItemRange(columnPositionStart,\n                columnHeaderModelList);\n    }\n\n    @NonNull\n    public List<C> getCellColumnItems(int columnPosition) {\n        return mCellRecyclerViewAdapter.getColumnItems(columnPosition);\n    }\n\n    public void removeColumn(int columnPosition) {\n        mColumnHeaderRecyclerViewAdapter.deleteItem(columnPosition);\n        mCellRecyclerViewAdapter.removeColumnItems(columnPosition);\n    }\n\n    public void addColumn(int columnPosition, @Nullable CH columnHeaderItem, @NonNull List<C> cellItems) {\n        mColumnHeaderRecyclerViewAdapter.addItem(columnPosition, columnHeaderItem);\n        mCellRecyclerViewAdapter.addColumnItems(columnPosition, cellItems);\n    }\n\n\n    public final void notifyDataSetChanged() {\n        mColumnHeaderRecyclerViewAdapter.notifyDataSetChanged();\n        mRowHeaderRecyclerViewAdapter.notifyDataSetChanged();\n        mCellRecyclerViewAdapter.notifyCellDataSetChanged();\n    }\n\n    @Override\n    public ITableView getTableView() {\n        return mTableView;\n    }\n\n    private void dispatchColumnHeaderDataSetChangesToListeners(@NonNull List<CH> newColumnHeaderItems) {\n        if (dataSetChangedListeners != null) {\n            for (AdapterDataSetChangedListener<CH, RH, C> listener : dataSetChangedListeners) {\n                listener.onColumnHeaderItemsChanged(newColumnHeaderItems);\n            }\n        }\n    }\n\n    private void dispatchRowHeaderDataSetChangesToListeners(@NonNull final List<RH> newRowHeaderItems) {\n        if (dataSetChangedListeners != null) {\n            for (AdapterDataSetChangedListener<CH, RH, C> listener : dataSetChangedListeners) {\n                listener.onRowHeaderItemsChanged(newRowHeaderItems);\n            }\n        }\n    }\n\n    private void dispatchCellDataSetChangesToListeners(@NonNull List<List<C>> newCellItems) {\n        if (dataSetChangedListeners != null) {\n            for (AdapterDataSetChangedListener<CH, RH, C> listener : dataSetChangedListeners) {\n                listener.onCellItemsChanged(newCellItems);\n            }\n        }\n    }\n\n    /**\n     * Sets the listener for changes of data set on the TableView.\n     *\n     * @param listener The AdapterDataSetChangedListener listener.\n     */\n    @Override\n    public void addAdapterDataSetChangedListener(@NonNull AdapterDataSetChangedListener<CH, RH, C> listener) {\n        if (dataSetChangedListeners == null) {\n            dataSetChangedListeners = new ArrayList<>();\n        }\n\n        dataSetChangedListeners.add(listener);\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/adapter/AdapterDataSetChangedListener.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.adapter;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.List;\n\npublic abstract class AdapterDataSetChangedListener<CH, RH, C> {\n\n    /**\n     * Dispatches changes on column header items to listener.\n     *\n     * @param columnHeaderItems The current column header items.\n     */\n    public void onColumnHeaderItemsChanged(@NonNull List<CH> columnHeaderItems) {\n    }\n\n    /**\n     * Dispatches changes on row header items to listener.\n     *\n     * @param rowHeaderItems The current row header items.\n     */\n    public void onRowHeaderItemsChanged(@NonNull List<RH> rowHeaderItems) {\n    }\n\n    /**\n     * Dispatches changes on cell items to listener.\n     *\n     * @param cellItems The current cell items.\n     */\n    public void onCellItemsChanged(@NonNull List<List<C>> cellItems) {\n    }\n\n    /**\n     * Dispatches the changes on column header, row header and cell items.\n     *\n     * @param columnHeaderItems The current column header items.\n     * @param rowHeaderItems    The current row header items.\n     * @param cellItems         The current cell items.\n     */\n    public void onDataSetChanged(\n            List<CH> columnHeaderItems,\n            List<RH> rowHeaderItems,\n            List<List<C>> cellItems) {\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/adapter/ITableAdapter.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.adapter;\n\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.evrencoskun.tableview.ITableView;\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder;\n\n/**\n * Created by evrencoskun on 10/06/2017.\n */\n\npublic interface ITableAdapter<CH, RH, C> {\n\n    int getColumnHeaderItemViewType(int position);\n\n    int getRowHeaderItemViewType(int position);\n\n    int getCellItemViewType(int position);\n\n    View getCornerView();\n\n    @NonNull\n    AbstractViewHolder onCreateCellViewHolder(@NonNull ViewGroup parent, int viewType);\n\n    void onBindCellViewHolder(@NonNull AbstractViewHolder holder, @Nullable C cellItemModel, int columnPosition, int rowPosition);\n\n    @NonNull\n    AbstractViewHolder onCreateColumnHeaderViewHolder(@NonNull ViewGroup parent, int viewType);\n\n    void onBindColumnHeaderViewHolder(@NonNull AbstractViewHolder holder, @Nullable CH columnHeaderItemModel, int columnPosition);\n\n    @NonNull\n    AbstractViewHolder onCreateRowHeaderViewHolder(@NonNull ViewGroup parent, int viewType);\n\n    void onBindRowHeaderViewHolder(@NonNull AbstractViewHolder holder, @Nullable RH rowHeaderItemModel, int rowPosition);\n\n    @NonNull\n    View onCreateCornerView(@NonNull ViewGroup parent);\n\n    ITableView getTableView();\n\n    /**\n     * Sets the listener for changes of data set on the TableView.\n     *\n     * @param listener The AdapterDataSetChangedListener listener.\n     */\n    void addAdapterDataSetChangedListener(@NonNull AdapterDataSetChangedListener<CH, RH, C> listener);\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/adapter/recyclerview/AbstractRecyclerViewAdapter.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.adapter.recyclerview;\n\nimport android.content.Context;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Created by evrencoskun on 10/06/2017.\n */\n\npublic abstract class AbstractRecyclerViewAdapter<T> extends RecyclerView\n        .Adapter<AbstractViewHolder> {\n\n    @NonNull\n    protected List<T> mItemList;\n\n    @NonNull\n    protected Context mContext;\n\n    public AbstractRecyclerViewAdapter(@NonNull Context context) {\n        this(context, null);\n    }\n\n    public AbstractRecyclerViewAdapter(@NonNull Context context, @Nullable List<T> itemList) {\n        mContext = context;\n\n        if (itemList == null) {\n            mItemList = new ArrayList<>();\n        } else {\n            setItems(itemList);\n        }\n    }\n\n    @Override\n    public int getItemCount() {\n        return mItemList.size();\n    }\n\n    @NonNull\n    public List<T> getItems() {\n        return mItemList;\n    }\n\n    public void setItems(@NonNull List<T> itemList) {\n        mItemList = new ArrayList<>(itemList);\n\n        this.notifyDataSetChanged();\n    }\n\n    public void setItems(@NonNull List<T> itemList, boolean notifyDataSet) {\n        mItemList = new ArrayList<>(itemList);\n\n        if (notifyDataSet) {\n            this.notifyDataSetChanged();\n        }\n    }\n\n    @Nullable\n    public T getItem(int position) {\n        if (mItemList.isEmpty() || position < 0 || position >= mItemList.size()) {\n            return null;\n        }\n        return mItemList.get(position);\n    }\n\n    public void deleteItem(int position) {\n        if (position != RecyclerView.NO_POSITION) {\n            mItemList.remove(position);\n            notifyItemRemoved(position);\n        }\n    }\n\n    public void deleteItemRange(int positionStart, int itemCount) {\n        for (int i = positionStart + itemCount - 1; i >= positionStart; i--) {\n            if (i != RecyclerView.NO_POSITION) {\n                mItemList.remove(i);\n            }\n        }\n\n        notifyItemRangeRemoved(positionStart, itemCount);\n    }\n\n    public void addItem(int position, @Nullable T item) {\n        if (position != RecyclerView.NO_POSITION && item != null) {\n            mItemList.add(position, item);\n            notifyItemInserted(position);\n        }\n    }\n\n    public void addItemRange(int positionStart, @Nullable List<T> items) {\n        if (items != null) {\n            for (int i = 0; i < items.size(); i++) {\n                mItemList.add((i + positionStart), items.get(i));\n            }\n\n            notifyItemRangeInserted(positionStart, items.size());\n        }\n    }\n\n    public void changeItem(int position, @Nullable T item) {\n        if (position != RecyclerView.NO_POSITION && item != null) {\n            mItemList.set(position, item);\n            notifyItemChanged(position);\n        }\n    }\n\n    public void changeItemRange(int positionStart, @Nullable List<T> items) {\n        if (items != null && mItemList.size() > positionStart + items.size()) {\n            for (int i = 0; i < items.size(); i++) {\n                mItemList.set(i + positionStart, items.get(i));\n            }\n            notifyItemRangeChanged(positionStart, items.size());\n        }\n    }\n\n    @Override\n    public int getItemViewType(int position) {\n        return 1;\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/adapter/recyclerview/CellRecyclerView.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.adapter.recyclerview;\n\nimport android.content.Context;\nimport android.util.Log;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.evrencoskun.tableview.R;\nimport com.evrencoskun.tableview.listener.scroll.HorizontalRecyclerViewListener;\nimport com.evrencoskun.tableview.listener.scroll.VerticalRecyclerViewListener;\n\n/**\n * Created by evrencoskun on 19/06/2017.\n */\n\npublic class CellRecyclerView extends RecyclerView {\n    private static final String LOG_TAG = CellRecyclerView.class.getSimpleName();\n\n    private int mScrolledX = 0;\n    private int mScrolledY = 0;\n\n    private boolean mIsHorizontalScrollListenerRemoved = true;\n    private boolean mIsVerticalScrollListenerRemoved = true;\n\n    public CellRecyclerView(@NonNull Context context) {\n        super(context);\n\n        // These are necessary.\n        this.setHasFixedSize(false);\n        this.setNestedScrollingEnabled(false);\n        // These are for better scrolling process.\n        this.setItemViewCacheSize(context.getResources().getInteger(R.integer\n                .default_item_cache_size));\n        this.setDrawingCacheEnabled(true);\n        this.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);\n    }\n\n    @Override\n    public void onScrolled(int dx, int dy) {\n        mScrolledX += dx;\n        mScrolledY += dy;\n\n        super.onScrolled(dx, dy);\n    }\n\n    public int getScrolledX() {\n        return mScrolledX;\n    }\n\n    public void clearScrolledX() {\n        mScrolledX = 0;\n    }\n\n    public int getScrolledY() {\n        return mScrolledY;\n    }\n\n    @Override\n    public void addOnScrollListener(@NonNull OnScrollListener listener) {\n        if (listener instanceof HorizontalRecyclerViewListener) {\n            if (mIsHorizontalScrollListenerRemoved) {\n                mIsHorizontalScrollListenerRemoved = false;\n                super.addOnScrollListener(listener);\n            } else {\n                // Do not let add the listener\n                Log.w(LOG_TAG, \"mIsHorizontalScrollListenerRemoved has been tried to add itself \"\n                        + \"before remove the old one\");\n            }\n        } else if (listener instanceof VerticalRecyclerViewListener) {\n            if (mIsVerticalScrollListenerRemoved) {\n                mIsVerticalScrollListenerRemoved = false;\n                super.addOnScrollListener(listener);\n            } else {\n                // Do not let add the listener\n                Log.w(LOG_TAG, \"mIsVerticalScrollListenerRemoved has been tried to add itself \" +\n                        \"before remove the old one\");\n            }\n        } else {\n            super.addOnScrollListener(listener);\n        }\n    }\n\n    @Override\n    public void removeOnScrollListener(@NonNull OnScrollListener listener) {\n        if (listener instanceof HorizontalRecyclerViewListener) {\n            if (mIsHorizontalScrollListenerRemoved) {\n                // Do not let remove the listener\n                Log.e(LOG_TAG, \"HorizontalRecyclerViewListener has been tried to remove \" +\n                        \"itself before add new one\");\n            } else {\n                mIsHorizontalScrollListenerRemoved = true;\n                super.removeOnScrollListener(listener);\n            }\n        } else if (listener instanceof VerticalRecyclerViewListener) {\n            if (mIsVerticalScrollListenerRemoved) {\n                // Do not let remove the listener\n                Log.e(LOG_TAG, \"mIsVerticalScrollListenerRemoved has been tried to remove \" +\n                        \"itself before add new one\");\n            } else {\n                mIsVerticalScrollListenerRemoved = true;\n                super.removeOnScrollListener(listener);\n            }\n        } else {\n            super.removeOnScrollListener(listener);\n        }\n    }\n\n    public boolean isHorizontalScrollListenerRemoved() {\n        return mIsHorizontalScrollListenerRemoved;\n    }\n\n    public boolean isScrollOthers() {\n        return !mIsHorizontalScrollListenerRemoved;\n    }\n\n    /**\n     * Begin a standard fling with an initial velocity along each axis in pixels per second.\n     * If the velocity given is below the system-defined minimum this method will return false\n     * and no fling will occur.\n     *\n     * @param velocityX Initial horizontal velocity in pixels per second\n     * @param velocityY Initial vertical velocity in pixels per second\n     * @return true if the fling was started, false if the velocity was too low to fling or\n     * LayoutManager does not support scrolling in the axis fling is issued.\n     * @see LayoutManager#canScrollVertically()\n     * @see LayoutManager#canScrollHorizontally()\n     */\n    @Override\n    public boolean fling(int velocityX, int velocityY) {\n        // Adjust speeds to be able to provide smoother scroll.\n        //velocityX *= 0.6;\n        //velocityY *= 0.6;\n        return super.fling(velocityX, velocityY);\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/adapter/recyclerview/CellRecyclerViewAdapter.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.adapter.recyclerview;\n\nimport android.content.Context;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.evrencoskun.tableview.ITableView;\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder;\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder.SelectionState;\nimport com.evrencoskun.tableview.handler.ScrollHandler;\nimport com.evrencoskun.tableview.handler.SelectionHandler;\nimport com.evrencoskun.tableview.layoutmanager.CellLayoutManager;\nimport com.evrencoskun.tableview.layoutmanager.ColumnLayoutManager;\nimport com.evrencoskun.tableview.listener.itemclick.CellRecyclerViewItemClickListener;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Created by evrencoskun on 10/06/2017.\n */\n\npublic class CellRecyclerViewAdapter<C> extends AbstractRecyclerViewAdapter<C> {\n    @NonNull\n    private final ITableView mTableView;\n\n    @NonNull\n    private final RecyclerView.RecycledViewPool mRecycledViewPool;\n\n    // This is for testing purpose\n    private int mRecyclerViewId = 0;\n\n    public CellRecyclerViewAdapter(@NonNull Context context, @Nullable List<C> itemList, @NonNull ITableView tableView) {\n        super(context, itemList);\n        this.mTableView = tableView;\n\n        // Create view pool to share Views between multiple RecyclerViews.\n        mRecycledViewPool = new RecyclerView.RecycledViewPool();\n        //TODO set the right value.\n        //mRecycledViewPool.setMaxRecycledViews(0, 110);\n    }\n\n    @NonNull\n    @Override\n    public AbstractViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n\n        // Create a RecyclerView as a Row of the CellRecyclerView\n        CellRecyclerView recyclerView = new CellRecyclerView(mContext);\n\n        // Use the same view pool\n        recyclerView.setRecycledViewPool(mRecycledViewPool);\n\n        if (mTableView.isShowHorizontalSeparators()) {\n            // Add divider\n            recyclerView.addItemDecoration(mTableView.getHorizontalItemDecoration());\n        }\n\n        // To get better performance for fixed size TableView\n        recyclerView.setHasFixedSize(mTableView.hasFixedWidth());\n\n        // set touch mHorizontalListener to scroll synchronously\n        recyclerView.addOnItemTouchListener(mTableView.getHorizontalRecyclerViewListener());\n\n        // Add Item click listener for cell views\n        if (mTableView.isAllowClickInsideCell()) {\n            recyclerView.addOnItemTouchListener(new CellRecyclerViewItemClickListener(recyclerView,\n                    mTableView));\n        }\n\n        // Set the Column layout manager that helps the fit width of the cell and column header\n        // and it also helps to locate the scroll position of the horizontal recyclerView\n        // which is row recyclerView\n        ColumnLayoutManager mColumnLayoutManager = new ColumnLayoutManager(mContext, mTableView);\n        if (mTableView.getReverseLayout()) mColumnLayoutManager.setReverseLayout(true);\n        recyclerView.setLayoutManager(mColumnLayoutManager);\n\n        // Create CellRow adapter\n        recyclerView.setAdapter(new CellRowRecyclerViewAdapter<>(mContext, mTableView));\n\n        // This is for testing purpose to find out which recyclerView is displayed.\n        recyclerView.setId(mRecyclerViewId);\n\n        mRecyclerViewId++;\n\n        return new CellRowViewHolder(recyclerView);\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull AbstractViewHolder holder, int yPosition) {\n        CellRowViewHolder viewHolder = (CellRowViewHolder) holder;\n        CellRowRecyclerViewAdapter viewAdapter = (CellRowRecyclerViewAdapter) viewHolder\n                .recyclerView.getAdapter();\n\n        // Get the list\n        List<C> rowList = (List<C>) mItemList.get(yPosition);\n\n        // Set Row position\n        viewAdapter.setYPosition(yPosition);\n\n        // Set the list to the adapter\n        viewAdapter.setItems(rowList);\n    }\n\n    @Override\n    public void onViewAttachedToWindow(@NonNull AbstractViewHolder holder) {\n        super.onViewAttachedToWindow(holder);\n\n        CellRowViewHolder viewHolder = (CellRowViewHolder) holder;\n\n        ScrollHandler scrollHandler = mTableView.getScrollHandler();\n\n        // The below code helps to display a new attached recyclerView on exact scrolled position.\n        ((ColumnLayoutManager) viewHolder.recyclerView.getLayoutManager())\n                .scrollToPositionWithOffset(scrollHandler.getColumnPosition(), scrollHandler\n                        .getColumnPositionOffset());\n\n        SelectionHandler selectionHandler = mTableView.getSelectionHandler();\n\n        if (selectionHandler.isAnyColumnSelected()) {\n\n            AbstractViewHolder cellViewHolder = (AbstractViewHolder) viewHolder.recyclerView\n                    .findViewHolderForAdapterPosition(selectionHandler.getSelectedColumnPosition());\n\n            if (cellViewHolder != null) {\n                // Control to ignore selection color\n                if (!mTableView.isIgnoreSelectionColors()) {\n                    cellViewHolder.setBackgroundColor(mTableView.getSelectedColor());\n                }\n                cellViewHolder.setSelected(SelectionState.SELECTED);\n\n            }\n        } else if (selectionHandler.isRowSelected(holder.getBindingAdapterPosition())) {\n            selectionHandler.changeSelectionOfRecyclerView(viewHolder.recyclerView,\n                    SelectionState.SELECTED, mTableView.getSelectedColor());\n        }\n\n    }\n\n    @Override\n    public void onViewDetachedFromWindow(@NonNull AbstractViewHolder holder) {\n        super.onViewDetachedFromWindow(holder);\n\n        // Clear selection status of the view holder\n        mTableView.getSelectionHandler().changeSelectionOfRecyclerView(((CellRowViewHolder)\n                holder).recyclerView, SelectionState.UNSELECTED, mTableView.getUnSelectedColor());\n    }\n\n    @Override\n    public void onViewRecycled(@NonNull AbstractViewHolder holder) {\n        super.onViewRecycled(holder);\n\n        CellRowViewHolder viewHolder = (CellRowViewHolder) holder;\n        // ScrolledX should be cleared at that time. Because we need to prepare each\n        // recyclerView\n        // at onViewAttachedToWindow process.\n        viewHolder.recyclerView.clearScrolledX();\n    }\n\n    static class CellRowViewHolder extends AbstractViewHolder {\n        final CellRecyclerView recyclerView;\n\n        CellRowViewHolder(@NonNull View itemView) {\n            super(itemView);\n            recyclerView = (CellRecyclerView) itemView;\n        }\n    }\n\n    public void notifyCellDataSetChanged() {\n        CellRecyclerView[] visibleRecyclerViews = mTableView.getCellLayoutManager()\n                .getVisibleCellRowRecyclerViews();\n\n        if (visibleRecyclerViews.length > 0) {\n            for (CellRecyclerView cellRowRecyclerView : visibleRecyclerViews) {\n                if (cellRowRecyclerView != null) {\n                    RecyclerView.Adapter adapter = cellRowRecyclerView.getAdapter();\n                    if (adapter != null) {\n                        adapter.notifyDataSetChanged();\n                    }\n                }\n            }\n        } else {\n            notifyDataSetChanged();\n        }\n    }\n\n    /**\n     * This method helps to get cell item model that is located on given column position.\n     *\n     * @param columnPosition\n     */\n    @NonNull\n    public List<C> getColumnItems(int columnPosition) {\n        List<C> cellItems = new ArrayList<>();\n\n        for (int i = 0; i < mItemList.size(); i++) {\n            List<C> rowList = (List<C>) mItemList.get(i);\n\n            if (rowList.size() > columnPosition) {\n                cellItems.add(rowList.get(columnPosition));\n            }\n        }\n\n        return cellItems;\n    }\n\n\n    public void removeColumnItems(int column) {\n\n        // Firstly, remove columns from visible recyclerViews.\n        // To be able provide removing animation, we need to notify just for given column position.\n        CellRecyclerView[] visibleRecyclerViews = mTableView.getCellLayoutManager()\n                .getVisibleCellRowRecyclerViews();\n\n        for (CellRecyclerView cellRowRecyclerView : visibleRecyclerViews) {\n            if (cellRowRecyclerView != null) {\n                AbstractRecyclerViewAdapter adapter = (AbstractRecyclerViewAdapter) cellRowRecyclerView.getAdapter();\n                if (adapter != null) {\n                    adapter.deleteItem(column);\n                }\n            }\n        }\n\n        // Lets change the model list silently\n        // Create a new list which the column is already removed.\n        List<List<C>> cellItems = new ArrayList<>();\n        for (int i = 0; i < mItemList.size(); i++) {\n            List<C> rowList = new ArrayList<>((List<C>) mItemList.get(i));\n\n            if (rowList.size() > column) {\n                rowList.remove(column);\n            }\n\n            cellItems.add(rowList);\n        }\n\n        // Change data without notifying. Because we already did for visible recyclerViews.\n        setItems((List<C>) cellItems, false);\n    }\n\n    public void addColumnItems(int column, @NonNull List<C> cellColumnItems) {\n        // It should be same size with exist model list.\n        if (cellColumnItems.size() != mItemList.size() || cellColumnItems.contains(null)) {\n            return;\n        }\n\n        // Firstly, add columns from visible recyclerViews.\n        // To be able provide removing animation, we need to notify just for given column position.\n        CellLayoutManager layoutManager = mTableView.getCellLayoutManager();\n        for (int i = layoutManager.findFirstVisibleItemPosition(); i < layoutManager\n                .findLastVisibleItemPosition() + 1; i++) {\n            // Get the cell row recyclerView that is located on i position\n            RecyclerView cellRowRecyclerView = (RecyclerView) layoutManager.findViewByPosition(i);\n\n            // Add the item using its adapter.\n            ((AbstractRecyclerViewAdapter) cellRowRecyclerView.getAdapter()).addItem(column,\n                    cellColumnItems.get(i));\n        }\n\n\n        // Lets change the model list silently\n        List<List<C>> cellItems = new ArrayList<>();\n        for (int i = 0; i < mItemList.size(); i++) {\n            List<C> rowList = new ArrayList<>((List<C>) mItemList.get(i));\n\n            if (rowList.size() > column) {\n                rowList.add(column, cellColumnItems.get(i));\n            }\n\n            cellItems.add(rowList);\n        }\n\n        // Change data without notifying. Because we already did for visible recyclerViews.\n        setItems((List<C>) cellItems, false);\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/adapter/recyclerview/CellRowRecyclerViewAdapter.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.adapter.recyclerview;\n\nimport android.content.Context;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\n\nimport com.evrencoskun.tableview.ITableView;\nimport com.evrencoskun.tableview.adapter.ITableAdapter;\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder;\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder.SelectionState;\n\n/**\n * Created by evrencoskun on 10/06/2017.\n */\n\npublic class CellRowRecyclerViewAdapter<C> extends AbstractRecyclerViewAdapter<C> {\n\n    private int mYPosition;\n    private final ITableAdapter mTableAdapter;\n\n    @NonNull\n    private final ITableView mTableView;\n\n    public CellRowRecyclerViewAdapter(@NonNull Context context, @NonNull ITableView tableView) {\n        super(context, null);\n        this.mTableAdapter = tableView.getAdapter();\n        this.mTableView = tableView;\n    }\n\n    @NonNull\n    @Override\n    public AbstractViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n        return mTableAdapter.onCreateCellViewHolder(parent, viewType);\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull final AbstractViewHolder holder, final int xPosition) {\n        mTableAdapter.onBindCellViewHolder(holder, getItem(xPosition), xPosition, mYPosition);\n    }\n\n    public int getYPosition() {\n        return mYPosition;\n    }\n\n    public void setYPosition(int rowPosition) {\n        mYPosition = rowPosition;\n    }\n\n    @Override\n    public int getItemViewType(int position) {\n        return mTableAdapter.getCellItemViewType(position);\n    }\n\n    @Override\n    public void onViewAttachedToWindow(@NonNull AbstractViewHolder viewHolder) {\n        super.onViewAttachedToWindow(viewHolder);\n\n        SelectionState selectionState = mTableView.getSelectionHandler().getCellSelectionState\n                (viewHolder.getBindingAdapterPosition(), mYPosition);\n\n        // Control to ignore selection color\n        if (!mTableView.isIgnoreSelectionColors()) {\n\n            // Change the background color of the view considering selected row/cell position.\n            if (selectionState == SelectionState.SELECTED) {\n                viewHolder.setBackgroundColor(mTableView.getSelectedColor());\n            } else {\n                viewHolder.setBackgroundColor(mTableView.getUnSelectedColor());\n            }\n        }\n\n        // Change selection status\n        viewHolder.setSelected(selectionState);\n    }\n\n    @Override\n    public boolean onFailedToRecycleView(@NonNull AbstractViewHolder holder) {\n        return holder.onFailedToRecycleView();\n    }\n\n    @Override\n    public void onViewRecycled(@NonNull AbstractViewHolder holder) {\n        super.onViewRecycled(holder);\n        holder.onViewRecycled();\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/adapter/recyclerview/ColumnHeaderRecyclerViewAdapter.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.adapter.recyclerview;\n\nimport android.content.Context;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.evrencoskun.tableview.ITableView;\nimport com.evrencoskun.tableview.adapter.ITableAdapter;\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractSorterViewHolder;\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder;\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder.SelectionState;\nimport com.evrencoskun.tableview.sort.ColumnSortHelper;\nimport com.evrencoskun.tableview.sort.SortState;\n\nimport java.util.List;\n\n/**\n * Created by evrencoskun on 10/06/2017.\n */\n\npublic class ColumnHeaderRecyclerViewAdapter<CH> extends AbstractRecyclerViewAdapter<CH> {\n    @NonNull\n    private final ITableAdapter mTableAdapter;\n    private final ITableView mTableView;\n    private ColumnSortHelper mColumnSortHelper;\n\n    public ColumnHeaderRecyclerViewAdapter(@NonNull Context context, @Nullable List<CH> itemList, @NonNull ITableAdapter\n            tableAdapter) {\n        super(context, itemList);\n        this.mTableAdapter = tableAdapter;\n        this.mTableView = tableAdapter.getTableView();\n    }\n\n    @NonNull\n    @Override\n    public AbstractViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n        return mTableAdapter.onCreateColumnHeaderViewHolder(parent, viewType);\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull AbstractViewHolder holder, int position) {\n        mTableAdapter.onBindColumnHeaderViewHolder(holder, getItem(position), position);\n    }\n\n    @Override\n    public int getItemViewType(int position) {\n        return mTableAdapter.getColumnHeaderItemViewType(position);\n    }\n\n    @Override\n    public void onViewAttachedToWindow(@NonNull AbstractViewHolder viewHolder) {\n        super.onViewAttachedToWindow(viewHolder);\n\n        SelectionState selectionState = mTableView.getSelectionHandler().getColumnSelectionState\n                (viewHolder.getBindingAdapterPosition());\n\n        // Control to ignore selection color\n        if (!mTableView.isIgnoreSelectionColors()) {\n\n            // Change background color of the view considering it's selected state\n            mTableView.getSelectionHandler().changeColumnBackgroundColorBySelectionStatus\n                    (viewHolder, selectionState);\n        }\n\n        // Change selection status\n        viewHolder.setSelected(selectionState);\n\n        // Control whether the TableView is sortable or not.\n        if (mTableView.isSortable()) {\n            if (viewHolder instanceof AbstractSorterViewHolder) {\n                // Get its sorting state\n                SortState state = getColumnSortHelper().getSortingStatus(viewHolder\n                        .getBindingAdapterPosition());\n                // Fire onSortingStatusChanged\n                ((AbstractSorterViewHolder) viewHolder).onSortingStatusChanged(state);\n            }\n        }\n    }\n\n    @NonNull\n    public ColumnSortHelper getColumnSortHelper() {\n        if (mColumnSortHelper == null) {\n            // It helps to store sorting state of column headers\n            this.mColumnSortHelper = new ColumnSortHelper(mTableView.getColumnHeaderLayoutManager\n                    ());\n        }\n        return mColumnSortHelper;\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/adapter/recyclerview/RowHeaderRecyclerViewAdapter.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.adapter.recyclerview;\n\nimport android.content.Context;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.evrencoskun.tableview.ITableView;\nimport com.evrencoskun.tableview.adapter.ITableAdapter;\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder;\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder.SelectionState;\nimport com.evrencoskun.tableview.sort.RowHeaderSortHelper;\n\nimport java.util.List;\n\n/**\n * Created by evrencoskun on 10/06/2017.\n */\n\npublic class RowHeaderRecyclerViewAdapter<RH> extends AbstractRecyclerViewAdapter<RH> {\n    @NonNull\n    private final ITableAdapter mTableAdapter;\n    private final ITableView mTableView;\n    private RowHeaderSortHelper mRowHeaderSortHelper;\n\n    public RowHeaderRecyclerViewAdapter(@NonNull Context context, @Nullable List<RH> itemList, @NonNull ITableAdapter\n            tableAdapter) {\n        super(context, itemList);\n        this.mTableAdapter = tableAdapter;\n        this.mTableView = tableAdapter.getTableView();\n    }\n\n    @NonNull\n    @Override\n    public AbstractViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n        return mTableAdapter.onCreateRowHeaderViewHolder(parent, viewType);\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull AbstractViewHolder holder, int position) {\n        mTableAdapter.onBindRowHeaderViewHolder(holder, getItem(position), position);\n    }\n\n    @Override\n    public int getItemViewType(int position) {\n        return mTableAdapter.getRowHeaderItemViewType(position);\n    }\n\n    @Override\n    public void onViewAttachedToWindow(@NonNull AbstractViewHolder viewHolder) {\n        super.onViewAttachedToWindow(viewHolder);\n\n        SelectionState selectionState = mTableView.getSelectionHandler().getRowSelectionState\n                (viewHolder.getBindingAdapterPosition());\n\n        // Control to ignore selection color\n        if (!mTableView.isIgnoreSelectionColors()) {\n\n            // Change background color of the view considering it's selected state\n            mTableView.getSelectionHandler().changeRowBackgroundColorBySelectionStatus\n                    (viewHolder, selectionState);\n        }\n\n        // Change selection status\n        viewHolder.setSelected(selectionState);\n    }\n\n    @NonNull\n    public RowHeaderSortHelper getRowHeaderSortHelper() {\n        if (mRowHeaderSortHelper == null) {\n            // It helps to store sorting state of row headers\n            this.mRowHeaderSortHelper = new RowHeaderSortHelper();\n        }\n        return mRowHeaderSortHelper;\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/adapter/recyclerview/holder/AbstractSorterViewHolder.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.adapter.recyclerview.holder;\n\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\n\nimport com.evrencoskun.tableview.sort.SortState;\n\n/**\n * Created by evrencoskun on 16.12.2017.\n */\n\npublic class AbstractSorterViewHolder extends AbstractViewHolder {\n    @NonNull\n    private SortState mSortState = SortState.UNSORTED;\n\n    public AbstractSorterViewHolder(@NonNull View itemView) {\n        super(itemView);\n    }\n\n    public void onSortingStatusChanged(@NonNull SortState pSortState) {\n        this.mSortState = pSortState;\n    }\n\n    @NonNull\n    public SortState getSortState() {\n        return mSortState;\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/adapter/recyclerview/holder/AbstractViewHolder.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.adapter.recyclerview.holder;\n\nimport android.view.View;\n\nimport androidx.annotation.ColorInt;\nimport androidx.annotation.NonNull;\nimport androidx.recyclerview.widget.RecyclerView;\n\n/**\n * Created by evrencoskun on 23/10/2017.\n */\n\npublic abstract class AbstractViewHolder extends RecyclerView.ViewHolder {\n    public enum SelectionState {SELECTED, UNSELECTED, SHADOWED}\n\n    // Default value\n    @NonNull\n    private SelectionState m_eState = SelectionState.UNSELECTED;\n\n    public AbstractViewHolder(@NonNull View itemView) {\n        super(itemView);\n    }\n\n    public void setSelected(@NonNull SelectionState selectionState) {\n        m_eState = selectionState;\n\n        if (selectionState == SelectionState.SELECTED) {\n            itemView.setSelected(true);\n        } else if (selectionState == SelectionState.UNSELECTED) {\n            itemView.setSelected(false);\n        }\n    }\n\n    public boolean isSelected() {\n        return m_eState == SelectionState.SELECTED;\n    }\n\n    public boolean isShadowed() {\n        return m_eState == SelectionState.SHADOWED;\n    }\n\n    public void setBackgroundColor(@ColorInt int p_nColor) {\n        itemView.setBackgroundColor(p_nColor);\n    }\n\n    public void onViewRecycled() {\n    }\n\n    public boolean onFailedToRecycleView() {\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/filter/Filter.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.filter;\n\nimport androidx.annotation.NonNull;\n\nimport com.evrencoskun.tableview.ITableView;\n\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\n\n/**\n * Class used to store multiple filters for the TableView filtering feature.\n */\npublic class Filter {\n\n    /**\n     * List of filter items to be used for filtering.\n     */\n    @NonNull\n    private final List<FilterItem> filterItems;\n\n    /**\n     * The TableView instance used in this scope.\n     */\n    @NonNull\n    private final ITableView tableView;\n\n    /**\n     * @param tableView The TableView to be filtered.\n     */\n    public Filter(@NonNull ITableView tableView) {\n        this.tableView = tableView;\n        this.filterItems = new ArrayList<>();\n    }\n\n    /**\n     * Adds new filter item to the list. This should be used strictly once\n     * for filtering the whole table.\n     *\n     * @param filter the filter string.\n     */\n    public void set(@NonNull String filter) {\n        set(-1, filter);\n    }\n\n    /**\n     * Adds new filter item to the list. The filter will be used on the\n     * specified column.\n     *\n     * @param column the target column for filtering.\n     * @param filter the filter string.\n     */\n    public void set(int column, @NonNull String filter) {\n        final FilterItem filterItem = new FilterItem(\n                column == -1 ? FilterType.ALL : FilterType.COLUMN,\n                column,\n                filter\n        );\n\n        if (isAlreadyFiltering(column, filterItem)) {\n            if (filter.isEmpty()) {\n                remove(column, filterItem);\n            } else {\n                update(column, filterItem);\n            }\n        } else if (!filter.isEmpty()) {\n            add(filterItem);\n        }\n    }\n\n    /**\n     * Adds new filter item to the list of this class.\n     *\n     * @param filterItem The filter item to be added to the list.\n     */\n    private void add(@NonNull FilterItem filterItem) {\n        filterItems.add(filterItem);\n        tableView.filter(this);\n    }\n\n    /**\n     * Removes a filter item from the list of this class.\n     *\n     * @param column     The column to be checked for removing the filter item.\n     * @param filterItem The filter item to be removed.\n     */\n    private void remove(int column, @NonNull FilterItem filterItem) {\n        // This would remove a FilterItem from the Filter list when the filter is cleared.\n        // Used Iterator for removing instead of canonical loop to prevent ConcurrentModificationException.\n        for (Iterator<FilterItem> filterItemIterator = filterItems.iterator(); filterItemIterator.hasNext(); ) {\n            final FilterItem item = filterItemIterator.next();\n            if (column == -1 && item.getFilterType().equals(filterItem.getFilterType())) {\n                filterItemIterator.remove();\n                break;\n            } else if (item.getColumn() == filterItem.getColumn()) {\n                filterItemIterator.remove();\n                break;\n            }\n        }\n        tableView.filter(this);\n    }\n\n    /**\n     * Updates a filter item from the list of this class.\n     *\n     * @param column     The column in which filter item will be updated.\n     * @param filterItem The updated filter item.\n     */\n    private void update(int column, @NonNull FilterItem filterItem) {\n        // This would update an existing FilterItem from the Filter list.\n        // Used Iterator for updating instead of canonical loop to prevent ConcurrentModificationException.\n        for (Iterator<FilterItem> filterItemIterator = filterItems.iterator(); filterItemIterator.hasNext(); ) {\n            final FilterItem item = filterItemIterator.next();\n            if (column == -1 && item.getFilterType().equals(filterItem.getFilterType())) {\n                filterItems.set(filterItems.indexOf(item), filterItem);\n                break;\n            } else if (item.getColumn() == filterItem.getColumn()) {\n                filterItems.set(filterItems.indexOf(item), filterItem);\n                break;\n            }\n        }\n        tableView.filter(this);\n    }\n\n    /**\n     * Method to check if a filter item is already added based on the column to be filtered.\n     *\n     * @param column     The column to be checked if the list is already filtering.\n     * @param filterItem The filter item to be checked.\n     * @return True if a filter item for a specific column or for ALL is already in the list.\n     */\n    private boolean isAlreadyFiltering(int column, @NonNull FilterItem filterItem) {\n        // This would determine if Filter is already filtering ALL or a specified COLUMN.\n        for (FilterItem item : filterItems) {\n            if (column == -1 && item.getFilterType().equals(filterItem.getFilterType())) {\n                return true;\n            } else if (item.getColumn() == filterItem.getColumn()) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Returns the list of filter items.\n     *\n     * @return The list of filter items.\n     */\n    @NonNull\n    public List<FilterItem> getFilterItems() {\n        return this.filterItems;\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/filter/FilterChangedListener.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.filter;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.List;\n\npublic abstract class FilterChangedListener<T> {\n\n    /**\n     * Called when a filter has been changed.\n     *\n     * @param filteredCellItems      The list of filtered cell items.\n     * @param filteredRowHeaderItems The list of filtered row items.\n     */\n    public void onFilterChanged(@NonNull List<List<T>> filteredCellItems, @NonNull List<T> filteredRowHeaderItems) {\n    }\n\n    /**\n     * Called when the TableView filters are cleared.\n     *\n     * @param originalCellItems      The unfiltered cell item list.\n     * @param originalRowHeaderItems The unfiltered row header list.\n     */\n    public void onFilterCleared(@NonNull List<List<T>> originalCellItems, @NonNull List<T> originalRowHeaderItems) {\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/filter/FilterItem.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.filter;\n\nimport androidx.annotation.NonNull;\n\npublic class FilterItem {\n    @NonNull\n    private final FilterType filterType;\n    @NonNull\n    private final String filter;\n    private final int column;\n\n    public FilterItem(@NonNull FilterType type, int column, @NonNull String filter) {\n        this.filterType = type;\n        this.column = column;\n        this.filter = filter;\n    }\n\n    @NonNull\n    public FilterType getFilterType() {\n        return filterType;\n    }\n\n    @NonNull\n    public String getFilter() {\n        return filter;\n    }\n\n    public int getColumn() {\n        return column;\n    }\n}"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/filter/FilterType.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.filter;\n\n/**\n * The type of filter based on the target.\n */\npublic enum FilterType {\n    /**\n     * Filters only a specific column.\n     */\n    COLUMN,\n    /**\n     * Filters all the data in the TableView.\n     */\n    ALL\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/filter/IFilterableModel.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.filter;\n\nimport androidx.annotation.NonNull;\n\npublic interface IFilterableModel {\n\n    /**\n     * Filterable query string for this object.\n     *\n     * @return query string for this object to be used in filtering.\n     */\n    @NonNull\n    String getFilterableKeyword();\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/handler/ColumnSortHandler.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.handler;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.recyclerview.widget.DiffUtil;\n\nimport com.evrencoskun.tableview.ITableView;\nimport com.evrencoskun.tableview.adapter.recyclerview.CellRecyclerViewAdapter;\nimport com.evrencoskun.tableview.adapter.recyclerview.ColumnHeaderRecyclerViewAdapter;\nimport com.evrencoskun.tableview.adapter.recyclerview.RowHeaderRecyclerViewAdapter;\nimport com.evrencoskun.tableview.sort.ColumnForRowHeaderSortComparator;\nimport com.evrencoskun.tableview.sort.ColumnSortCallback;\nimport com.evrencoskun.tableview.sort.ColumnSortComparator;\nimport com.evrencoskun.tableview.sort.ColumnSortStateChangedListener;\nimport com.evrencoskun.tableview.sort.ISortableModel;\nimport com.evrencoskun.tableview.sort.RowHeaderForCellSortComparator;\nimport com.evrencoskun.tableview.sort.RowHeaderSortCallback;\nimport com.evrencoskun.tableview.sort.RowHeaderSortComparator;\nimport com.evrencoskun.tableview.sort.SortState;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * Created by evrencoskun on 24.11.2017.\n */\n\npublic class ColumnSortHandler {\n\n    private final CellRecyclerViewAdapter<List<ISortableModel>> mCellRecyclerViewAdapter;\n    private final RowHeaderRecyclerViewAdapter<ISortableModel> mRowHeaderRecyclerViewAdapter;\n    private final ColumnHeaderRecyclerViewAdapter mColumnHeaderRecyclerViewAdapter;\n\n    private List<ColumnSortStateChangedListener> columnSortStateChangedListeners = new ArrayList<>();\n    private boolean mEnableAnimation = true;\n\n    public boolean isEnableAnimation() {\n        return mEnableAnimation;\n    }\n\n    public void setEnableAnimation(boolean mEnableAnimation) {\n        this.mEnableAnimation = mEnableAnimation;\n    }\n\n    public ColumnSortHandler(@NonNull ITableView tableView) {\n        this.mCellRecyclerViewAdapter = (CellRecyclerViewAdapter<List<ISortableModel>>) tableView.getCellRecyclerView()\n                .getAdapter();\n\n        this.mRowHeaderRecyclerViewAdapter = (RowHeaderRecyclerViewAdapter<ISortableModel>) tableView\n                .getRowHeaderRecyclerView().getAdapter();\n\n        this.mColumnHeaderRecyclerViewAdapter = (ColumnHeaderRecyclerViewAdapter) tableView\n                .getColumnHeaderRecyclerView().getAdapter();\n    }\n\n    public void sortByRowHeader(@NonNull final SortState sortState) {\n        List<ISortableModel> originalRowHeaderList = mRowHeaderRecyclerViewAdapter.getItems();\n        List<ISortableModel> sortedRowHeaderList = new ArrayList<>(originalRowHeaderList);\n\n        List<List<ISortableModel>> originalList = mCellRecyclerViewAdapter.getItems();\n        List<List<ISortableModel>> sortedList = new ArrayList<>(originalList);\n\n        if (sortState != SortState.UNSORTED) {\n            // Do descending / ascending sort\n            Collections.sort(sortedRowHeaderList, new RowHeaderSortComparator(sortState));\n\n            // Sorting Columns/Cells using the same logic has sorting DataSet\n            RowHeaderForCellSortComparator rowHeaderForCellSortComparator\n                    = new RowHeaderForCellSortComparator(\n                    originalRowHeaderList,\n                    originalList,\n                    sortState);\n\n            Collections.sort(sortedList, rowHeaderForCellSortComparator);\n        }\n\n        mRowHeaderRecyclerViewAdapter.getRowHeaderSortHelper().setSortingStatus(sortState);\n\n        // Set sorted data list\n        swapItems(originalRowHeaderList, sortedRowHeaderList, sortedList, sortState);\n    }\n\n    public void sort(int column, @NonNull SortState sortState) {\n        List<List<ISortableModel>> originalList = mCellRecyclerViewAdapter.getItems();\n        List<List<ISortableModel>> sortedList = new ArrayList<>(originalList);\n\n        List<ISortableModel> originalRowHeaderList\n                = mRowHeaderRecyclerViewAdapter.getItems();\n        List<ISortableModel> sortedRowHeaderList\n                = new ArrayList<>(originalRowHeaderList);\n\n        if (sortState != SortState.UNSORTED) {\n            // Do descending / ascending sort\n            Collections.sort(sortedList, new ColumnSortComparator(column, sortState));\n\n            // Sorting RowHeader using the same logic has sorting DataSet\n            ColumnForRowHeaderSortComparator columnForRowHeaderSortComparator\n                    = new ColumnForRowHeaderSortComparator(\n                    originalRowHeaderList,\n                    originalList,\n                    column,\n                    sortState);\n\n            Collections.sort(sortedRowHeaderList, columnForRowHeaderSortComparator);\n        }\n\n        // Update sorting list of column headers\n        mColumnHeaderRecyclerViewAdapter.getColumnSortHelper().setSortingStatus(column, sortState);\n\n        // Set sorted data list\n        swapItems(originalList, sortedList, column, sortedRowHeaderList, sortState);\n    }\n\n    private void swapItems(@NonNull List<ISortableModel> oldRowHeader,\n                           @NonNull List<ISortableModel> newRowHeader,\n                           @NonNull List<List<ISortableModel>> newColumnItems,\n                           @NonNull SortState sortState\n    ) {\n\n        // Set new items without calling notifyCellDataSetChanged method of CellRecyclerViewAdapter\n        mRowHeaderRecyclerViewAdapter.setItems(newRowHeader, !mEnableAnimation);\n        mCellRecyclerViewAdapter.setItems(newColumnItems, !mEnableAnimation);\n\n        if (mEnableAnimation) {\n            // Find the differences between old cell items and new items.\n            final RowHeaderSortCallback diffCallback = new RowHeaderSortCallback(oldRowHeader, newRowHeader);\n            final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallback);\n\n            diffResult.dispatchUpdatesTo(mRowHeaderRecyclerViewAdapter);\n            diffResult.dispatchUpdatesTo(mCellRecyclerViewAdapter);\n        }\n\n        for (ColumnSortStateChangedListener listener : columnSortStateChangedListeners) {\n            listener.onRowHeaderSortStatusChanged(sortState);\n        }\n    }\n\n    private void swapItems(@NonNull List<List<ISortableModel>> oldItems, @NonNull List<List<ISortableModel>>\n            newItems, int column, @NonNull List<ISortableModel> newRowHeader, @NonNull SortState sortState) {\n\n        // Set new items without calling notifyCellDataSetChanged method of CellRecyclerViewAdapter\n        mCellRecyclerViewAdapter.setItems(newItems, !mEnableAnimation);\n        mRowHeaderRecyclerViewAdapter.setItems(newRowHeader, !mEnableAnimation);\n\n        if (mEnableAnimation) {\n            // Find the differences between old cell items and new items.\n            final ColumnSortCallback diffCallback = new ColumnSortCallback(oldItems, newItems, column);\n            final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallback);\n\n            diffResult.dispatchUpdatesTo(mCellRecyclerViewAdapter);\n            diffResult.dispatchUpdatesTo(mRowHeaderRecyclerViewAdapter);\n        }\n\n        for (ColumnSortStateChangedListener listener : columnSortStateChangedListeners) {\n            listener.onColumnSortStatusChanged(column, sortState);\n        }\n    }\n\n    public void swapItems(@NonNull List<List<ISortableModel>> newItems, int column) {\n\n        List<List<ISortableModel>> oldItems = mCellRecyclerViewAdapter.getItems();\n\n        // Set new items without calling notifyCellDataSetChanged method of CellRecyclerViewAdapter\n        mCellRecyclerViewAdapter.setItems(newItems, !mEnableAnimation);\n\n        if (mEnableAnimation) {\n            // Find the differences between old cell items and new items.\n            final ColumnSortCallback diffCallback = new ColumnSortCallback(oldItems, newItems, column);\n            final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallback);\n\n            diffResult.dispatchUpdatesTo(mCellRecyclerViewAdapter);\n            diffResult.dispatchUpdatesTo(mRowHeaderRecyclerViewAdapter);\n        }\n\n    }\n\n    @NonNull\n    public SortState getSortingStatus(int column) {\n        return mColumnHeaderRecyclerViewAdapter.getColumnSortHelper().getSortingStatus(column);\n    }\n\n    @Nullable\n    public SortState getRowHeaderSortingStatus() {\n        return mRowHeaderRecyclerViewAdapter.getRowHeaderSortHelper().getSortingStatus();\n    }\n\n    /**\n     * Sets the listener for the changes in column sorting.\n     *\n     * @param listener ColumnSortStateChangedListener listener.\n     */\n    public void addColumnSortStateChangedListener(@NonNull ColumnSortStateChangedListener listener) {\n        if (columnSortStateChangedListeners == null) {\n            columnSortStateChangedListeners = new ArrayList<>();\n        }\n\n        columnSortStateChangedListeners.add(listener);\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/handler/ColumnWidthHandler.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.handler;\n\nimport androidx.annotation.NonNull;\n\nimport com.evrencoskun.tableview.ITableView;\n\n/**\n * Created by evrencoskun on 25.04.2018.\n */\n\npublic class ColumnWidthHandler {\n    @NonNull\n    private final ITableView mTableView;\n\n    public ColumnWidthHandler(@NonNull ITableView tableView) {\n        mTableView = tableView;\n    }\n\n    public void setColumnWidth(int columnPosition, int width) {\n\n        // Firstly set the column header cache map\n        mTableView.getColumnHeaderLayoutManager().setCacheWidth(columnPosition, width);\n\n        // Set each of cell items that is located on the column position\n        mTableView.getCellLayoutManager().setCacheWidth(columnPosition, width);\n    }\n\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/handler/FilterHandler.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.handler;\n\nimport androidx.annotation.NonNull;\n\nimport com.evrencoskun.tableview.ITableView;\nimport com.evrencoskun.tableview.adapter.AdapterDataSetChangedListener;\nimport com.evrencoskun.tableview.adapter.recyclerview.CellRecyclerViewAdapter;\nimport com.evrencoskun.tableview.adapter.recyclerview.RowHeaderRecyclerViewAdapter;\nimport com.evrencoskun.tableview.filter.Filter;\nimport com.evrencoskun.tableview.filter.FilterChangedListener;\nimport com.evrencoskun.tableview.filter.FilterItem;\nimport com.evrencoskun.tableview.filter.FilterType;\nimport com.evrencoskun.tableview.filter.IFilterableModel;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class FilterHandler<T extends IFilterableModel> {\n\n    private final CellRecyclerViewAdapter<List<T>> mCellRecyclerViewAdapter;\n    private final RowHeaderRecyclerViewAdapter<T> mRowHeaderRecyclerViewAdapter;\n    private List<List<T>> originalCellDataStore;\n    private List<T> originalRowDataStore;\n\n    private List<FilterChangedListener<T>> filterChangedListeners;\n\n    public FilterHandler(@NonNull ITableView tableView) {\n        tableView.getAdapter().addAdapterDataSetChangedListener(adapterDataSetChangedListener);\n        this.mCellRecyclerViewAdapter = (CellRecyclerViewAdapter<List<T>>) tableView\n                .getCellRecyclerView().getAdapter();\n\n        this.mRowHeaderRecyclerViewAdapter = (RowHeaderRecyclerViewAdapter<T>) tableView\n                .getRowHeaderRecyclerView().getAdapter();\n    }\n\n    public void filter(@NonNull Filter filter) {\n        if (originalCellDataStore == null || originalRowDataStore == null) {\n            return;\n        }\n\n        List<List<T>> originalCellData = new ArrayList<>(originalCellDataStore);\n        List<T> originalRowData = new ArrayList<>(originalRowDataStore);\n        List<List<T>> filteredCellList = new ArrayList<>();\n        List<T> filteredRowList = new ArrayList<>();\n\n        if (filter.getFilterItems().isEmpty()) {\n            filteredCellList = new ArrayList<>(originalCellDataStore);\n            filteredRowList = new ArrayList<>(originalRowDataStore);\n            dispatchFilterClearedToListeners(originalCellDataStore, originalRowDataStore);\n        } else {\n            for (int x = 0; x < filter.getFilterItems().size(); ) {\n                final FilterItem filterItem = filter.getFilterItems().get(x);\n                if (filterItem.getFilterType().equals(FilterType.ALL)) {\n                    for (List<T> itemsList : originalCellData) {\n                        for (T item : itemsList) {\n                            if (item\n                                    .getFilterableKeyword()\n                                    .toLowerCase()\n                                    .contains(filterItem\n                                            .getFilter()\n                                            .toLowerCase())) {\n                                filteredCellList.add(itemsList);\n                                filteredRowList.add(originalRowData.get(filteredCellList.indexOf(itemsList)));\n                                break;\n                            }\n                        }\n                    }\n                } else {\n                    for (List<T> itemsList : originalCellData) {\n                        if (itemsList\n                                .get(filterItem\n                                        .getColumn())\n                                .getFilterableKeyword()\n                                .toLowerCase()\n                                .contains(filterItem\n                                        .getFilter()\n                                        .toLowerCase())) {\n                            filteredCellList.add(itemsList);\n                            filteredRowList.add(originalRowData.get(filteredCellList.indexOf(itemsList)));\n                        }\n                    }\n                }\n\n                // If this is the last filter to be processed, the filtered lists will not be cleared.\n                if (++x < filter.getFilterItems().size()) {\n                    originalCellData = new ArrayList<>(filteredCellList);\n                    originalRowData = new ArrayList<>(filteredRowList);\n                    filteredCellList.clear();\n                    filteredRowList.clear();\n                }\n            }\n        }\n\n        // Sets the filtered data to the TableView.\n        mRowHeaderRecyclerViewAdapter.setItems(filteredRowList, true);\n        mCellRecyclerViewAdapter.setItems(filteredCellList, true);\n\n        // Tells the listeners that the TableView is filtered.\n        dispatchFilterChangedToListeners(filteredCellList, filteredRowList);\n    }\n\n    @NonNull\n    @SuppressWarnings(\"unchecked\")\n    private final AdapterDataSetChangedListener adapterDataSetChangedListener =\n            new AdapterDataSetChangedListener() {\n                @Override\n                public void onRowHeaderItemsChanged(@NonNull List rowHeaderItems) {\n                    originalRowDataStore = new ArrayList<>(rowHeaderItems);\n                }\n\n                @Override\n                public void onCellItemsChanged(@NonNull List cellItems) {\n                    originalCellDataStore = new ArrayList<>(cellItems);\n                }\n            };\n\n    private void dispatchFilterChangedToListeners(\n            @NonNull List<List<T>> filteredCellItems,\n            @NonNull List<T> filteredRowHeaderItems\n    ) {\n        if (filterChangedListeners != null) {\n            for (FilterChangedListener<T> listener : filterChangedListeners) {\n                listener.onFilterChanged(filteredCellItems, filteredRowHeaderItems);\n            }\n        }\n    }\n\n    private void dispatchFilterClearedToListeners(\n            @NonNull List<List<T>> originalCellItems,\n            @NonNull List<T> originalRowHeaderItems\n    ) {\n        if (filterChangedListeners != null) {\n            for (FilterChangedListener<T> listener : filterChangedListeners) {\n                listener.onFilterCleared(originalCellItems, originalRowHeaderItems);\n            }\n        }\n    }\n\n    public void addFilterChangedListener(@NonNull FilterChangedListener<T> listener) {\n        if (filterChangedListeners == null) {\n            filterChangedListeners = new ArrayList<>();\n        }\n\n        filterChangedListeners.add(listener);\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/handler/PreferencesHandler.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.handler;\n\nimport androidx.annotation.NonNull;\n\nimport com.evrencoskun.tableview.TableView;\nimport com.evrencoskun.tableview.preference.Preferences;\n\n/**\n * Created by evrencoskun on 3.03.2018.\n */\n\npublic class PreferencesHandler {\n    @NonNull\n    private final ScrollHandler scrollHandler;\n    @NonNull\n    private final SelectionHandler selectionHandler;\n\n    public PreferencesHandler(@NonNull TableView tableView) {\n        this.scrollHandler = tableView.getScrollHandler();\n        this.selectionHandler = tableView.getSelectionHandler();\n    }\n\n    @NonNull\n    public Preferences savePreferences() {\n        Preferences preferences = new Preferences();\n        preferences.columnPosition = scrollHandler.getColumnPosition();\n        preferences.columnPositionOffset = scrollHandler.getColumnPositionOffset();\n        preferences.rowPosition = scrollHandler.getRowPosition();\n        preferences.rowPositionOffset = scrollHandler.getRowPositionOffset();\n        preferences.selectedColumnPosition = selectionHandler.getSelectedColumnPosition();\n        preferences.selectedRowPosition = selectionHandler.getSelectedRowPosition();\n        return preferences;\n    }\n\n    public void loadPreferences(@NonNull Preferences preferences) {\n        scrollHandler.scrollToColumnPosition(preferences.columnPosition, preferences.columnPositionOffset);\n        scrollHandler.scrollToRowPosition(preferences.rowPosition, preferences.rowPositionOffset);\n        selectionHandler.setSelectedColumnPosition(preferences.selectedColumnPosition);\n        selectionHandler.setSelectedRowPosition(preferences.selectedRowPosition);\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/handler/ScrollHandler.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.handler;\n\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.evrencoskun.tableview.ITableView;\nimport com.evrencoskun.tableview.layoutmanager.CellLayoutManager;\nimport com.evrencoskun.tableview.layoutmanager.ColumnHeaderLayoutManager;\nimport com.evrencoskun.tableview.layoutmanager.ColumnLayoutManager;\n\n/**\n * Created by evrencoskun on 13.01.2018.\n */\n\npublic class ScrollHandler {\n    @NonNull\n    private final ITableView mTableView;\n    @NonNull\n    private final CellLayoutManager mCellLayoutManager;\n    @NonNull\n    private final LinearLayoutManager mRowHeaderLayoutManager;\n    @NonNull\n    private final ColumnHeaderLayoutManager mColumnHeaderLayoutManager;\n\n    public ScrollHandler(@NonNull ITableView tableView) {\n        this.mTableView = tableView;\n        this.mCellLayoutManager = tableView.getCellLayoutManager();\n        this.mRowHeaderLayoutManager = tableView.getRowHeaderLayoutManager();\n        this.mColumnHeaderLayoutManager = tableView.getColumnHeaderLayoutManager();\n    }\n\n    public void scrollToColumnPosition(int columnPosition) {\n        // TableView is not on screen yet.\n        if (!((View) mTableView).isShown()) {\n            // Change default value of the listener\n            mTableView.getHorizontalRecyclerViewListener().setScrollPosition(columnPosition);\n        }\n\n        // Column Header should be scrolled firstly because of fitting column width process.\n        scrollColumnHeader(columnPosition, 0);\n        scrollCellHorizontally(columnPosition, 0);\n    }\n\n    public void scrollToColumnPosition(int columnPosition, int offset) {\n        // TableView is not on screen yet.\n        if (!((View) mTableView).isShown()) {\n            // Change default value of the listener\n            mTableView.getHorizontalRecyclerViewListener().setScrollPosition(columnPosition);\n            mTableView.getHorizontalRecyclerViewListener().setScrollPositionOffset(offset);\n        }\n\n        // Column Header should be scrolled firstly because of fitting column width process.\n        scrollColumnHeader(columnPosition, offset);\n        scrollCellHorizontally(columnPosition, offset);\n    }\n\n    public void scrollToRowPosition(int rowPosition) {\n        mRowHeaderLayoutManager.scrollToPosition(rowPosition);\n        mCellLayoutManager.scrollToPosition(rowPosition);\n    }\n\n    public void scrollToRowPosition(int rowPosition, int offset) {\n        mRowHeaderLayoutManager.scrollToPositionWithOffset(rowPosition, offset);\n        mCellLayoutManager.scrollToPositionWithOffset(rowPosition, offset);\n    }\n\n    private void scrollCellHorizontally(int columnPosition, int offset) {\n        CellLayoutManager cellLayoutManager = mTableView.getCellLayoutManager();\n\n        for (int i = cellLayoutManager.findFirstVisibleItemPosition(); i < cellLayoutManager\n                .findLastVisibleItemPosition() + 1; i++) {\n\n            RecyclerView cellRowRecyclerView = (RecyclerView) cellLayoutManager\n                    .findViewByPosition(i);\n\n            if (cellRowRecyclerView != null) {\n                ColumnLayoutManager columnLayoutManager = (ColumnLayoutManager)\n                        cellRowRecyclerView.getLayoutManager();\n\n                columnLayoutManager.scrollToPositionWithOffset(columnPosition, offset);\n            }\n\n        }\n    }\n\n    private void scrollColumnHeader(int columnPosition, int offset) {\n        mTableView.getColumnHeaderLayoutManager().scrollToPositionWithOffset(columnPosition,\n                offset);\n    }\n\n    public int getColumnPosition() {\n        return mColumnHeaderLayoutManager.findFirstVisibleItemPosition();\n    }\n\n    public int getColumnPositionOffset() {\n        View child = mColumnHeaderLayoutManager.findViewByPosition(mColumnHeaderLayoutManager\n                .findFirstVisibleItemPosition());\n        if (child != null) {\n            return child.getLeft();\n        }\n        return 0;\n    }\n\n    public int getRowPosition() {\n        return mRowHeaderLayoutManager.findFirstVisibleItemPosition();\n    }\n\n    public int getRowPositionOffset() {\n        View child = mRowHeaderLayoutManager.findViewByPosition(mRowHeaderLayoutManager\n                .findFirstVisibleItemPosition());\n        if (child != null) {\n            return child.getLeft();\n        }\n        return 0;\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/handler/SelectionHandler.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.handler;\n\nimport androidx.annotation.ColorInt;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.recyclerview.widget.LinearLayoutManager;\n\nimport com.evrencoskun.tableview.ITableView;\nimport com.evrencoskun.tableview.adapter.recyclerview.CellRecyclerView;\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder;\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder.SelectionState;\nimport com.evrencoskun.tableview.layoutmanager.CellLayoutManager;\n\n/**\n * Created by evrencoskun on 24/10/2017.\n */\n\npublic class SelectionHandler {\n\n    public static final int UNSELECTED_POSITION = -1;\n    private int mSelectedRowPosition = UNSELECTED_POSITION;\n    private int mSelectedColumnPosition = UNSELECTED_POSITION;\n\n    private boolean shadowEnabled = true;\n\n    @NonNull\n    private final ITableView mTableView;\n    private AbstractViewHolder mPreviousSelectedViewHolder;\n    @NonNull\n    private final CellRecyclerView mColumnHeaderRecyclerView;\n    @NonNull\n    private final CellRecyclerView mRowHeaderRecyclerView;\n    @NonNull\n    private final CellLayoutManager mCellLayoutManager;\n\n    public SelectionHandler(@NonNull ITableView tableView) {\n        this.mTableView = tableView;\n        this.mColumnHeaderRecyclerView = mTableView.getColumnHeaderRecyclerView();\n        this.mRowHeaderRecyclerView = mTableView.getRowHeaderRecyclerView();\n        this.mCellLayoutManager = mTableView.getCellLayoutManager();\n    }\n\n    public boolean isShadowEnabled() {\n        return shadowEnabled;\n    }\n\n    public void setShadowEnabled(boolean shadowEnabled) {\n        this.shadowEnabled = shadowEnabled;\n    }\n\n    public void setSelectedCellPositions(@Nullable AbstractViewHolder selectedViewHolder, int column, int\n            row) {\n        this.setPreviousSelectedView(selectedViewHolder);\n\n        this.mSelectedColumnPosition = column;\n        this.mSelectedRowPosition = row;\n\n        if (shadowEnabled) {\n            selectedCellView();\n        }\n    }\n\n    public void setSelectedColumnPosition(@Nullable AbstractViewHolder selectedViewHolder, int column) {\n        this.setPreviousSelectedView(selectedViewHolder);\n\n        this.mSelectedColumnPosition = column;\n\n        selectedColumnHeader();\n\n        // Set unselected others\n        mSelectedRowPosition = UNSELECTED_POSITION;\n    }\n\n    public int getSelectedColumnPosition() {\n        return mSelectedColumnPosition;\n    }\n\n    public void setSelectedRowPosition(@Nullable AbstractViewHolder selectedViewHolder, int row) {\n        this.setPreviousSelectedView(selectedViewHolder);\n\n        this.mSelectedRowPosition = row;\n\n        selectedRowHeader();\n\n        // Set unselected others\n        mSelectedColumnPosition = UNSELECTED_POSITION;\n    }\n\n    public int getSelectedRowPosition() {\n        return mSelectedRowPosition;\n    }\n\n    public void setPreviousSelectedView(@Nullable AbstractViewHolder viewHolder) {\n        restorePreviousSelectedView();\n\n        if (mPreviousSelectedViewHolder != null) {\n            // Change color\n            mPreviousSelectedViewHolder.setBackgroundColor(mTableView.getUnSelectedColor());\n            // Change state\n            mPreviousSelectedViewHolder.setSelected(SelectionState.UNSELECTED);\n        }\n\n        AbstractViewHolder oldViewHolder = mCellLayoutManager.getCellViewHolder\n                (getSelectedColumnPosition(), getSelectedRowPosition());\n\n        if (oldViewHolder != null) {\n            // Change color\n            oldViewHolder.setBackgroundColor(mTableView.getUnSelectedColor());\n            // Change state\n            oldViewHolder.setSelected(SelectionState.UNSELECTED);\n        }\n\n        this.mPreviousSelectedViewHolder = viewHolder;\n\n        // Change color\n        mPreviousSelectedViewHolder.setBackgroundColor(mTableView.getSelectedColor());\n        // Change state\n        mPreviousSelectedViewHolder.setSelected(SelectionState.SELECTED);\n    }\n\n    private void restorePreviousSelectedView() {\n        if (mSelectedColumnPosition != UNSELECTED_POSITION && mSelectedRowPosition !=\n                UNSELECTED_POSITION) {\n            unselectedCellView();\n        } else if (mSelectedColumnPosition != UNSELECTED_POSITION) {\n            unselectedColumnHeader();\n        } else if (mSelectedRowPosition != UNSELECTED_POSITION) {\n            unselectedRowHeader();\n        }\n    }\n\n    private void selectedRowHeader() {\n        // Change background color of the selected cell views\n        changeVisibleCellViewsBackgroundForRow(mSelectedRowPosition, true);\n\n        // Change background color of the column headers to be shown as a shadow.\n        if (shadowEnabled) {\n            changeSelectionOfRecyclerView(mColumnHeaderRecyclerView, SelectionState.SHADOWED,\n                    mTableView.getShadowColor());\n        }\n    }\n\n    private void unselectedRowHeader() {\n        changeVisibleCellViewsBackgroundForRow(mSelectedRowPosition, false);\n\n        // Change background color of the column headers to be shown as a normal.\n        changeSelectionOfRecyclerView(mColumnHeaderRecyclerView, SelectionState.UNSELECTED,\n                mTableView.getUnSelectedColor());\n    }\n\n    private void selectedCellView() {\n        int shadowColor = mTableView.getShadowColor();\n\n        // Change background color of the row header which is located on Y Position of the cell\n        // view.\n        AbstractViewHolder rowHeader = (AbstractViewHolder) mRowHeaderRecyclerView\n                .findViewHolderForAdapterPosition(mSelectedRowPosition);\n\n        // If view is null, that means the row view holder was already recycled.\n        if (rowHeader != null) {\n            // Change color\n            rowHeader.setBackgroundColor(shadowColor);\n            // Change state\n            rowHeader.setSelected(SelectionState.SHADOWED);\n        }\n\n        // Change background color of the column header which is located on X Position of the cell\n        // view.\n        AbstractViewHolder columnHeader = (AbstractViewHolder) mColumnHeaderRecyclerView\n                .findViewHolderForAdapterPosition(mSelectedColumnPosition);\n\n        if (columnHeader != null) {\n            // Change color\n            columnHeader.setBackgroundColor(shadowColor);\n            // Change state\n            columnHeader.setSelected(SelectionState.SHADOWED);\n        }\n\n    }\n\n    private void unselectedCellView() {\n        int unSelectedColor = mTableView.getUnSelectedColor();\n\n        // Change background color of the row header which is located on Y Position of the cell\n        // view.\n        AbstractViewHolder rowHeader = (AbstractViewHolder) mRowHeaderRecyclerView\n                .findViewHolderForAdapterPosition(mSelectedRowPosition);\n\n        // If view is null, that means the row view holder was already recycled.\n        if (rowHeader != null) {\n            // Change color\n            rowHeader.setBackgroundColor(unSelectedColor);\n            // Change state\n            rowHeader.setSelected(SelectionState.UNSELECTED);\n        }\n\n        // Change background color of the column header which is located on X Position of the cell\n        // view.\n        AbstractViewHolder columnHeader = (AbstractViewHolder) mColumnHeaderRecyclerView\n                .findViewHolderForAdapterPosition(mSelectedColumnPosition);\n\n        if (columnHeader != null) {\n            // Change color\n            columnHeader.setBackgroundColor(unSelectedColor);\n            // Change state\n            columnHeader.setSelected(SelectionState.UNSELECTED);\n        }\n    }\n\n    private void selectedColumnHeader() {\n        changeVisibleCellViewsBackgroundForColumn(mSelectedColumnPosition, true);\n\n        changeSelectionOfRecyclerView(mRowHeaderRecyclerView, SelectionState.SHADOWED, mTableView\n                .getShadowColor());\n    }\n\n    private void unselectedColumnHeader() {\n        changeVisibleCellViewsBackgroundForColumn(mSelectedColumnPosition, false);\n\n        changeSelectionOfRecyclerView(mRowHeaderRecyclerView, SelectionState.UNSELECTED,\n                mTableView.getUnSelectedColor());\n    }\n\n    public boolean isCellSelected(int column, int row) {\n        return (getSelectedColumnPosition() == column && getSelectedRowPosition() == row) ||\n                isColumnSelected(column) || isRowSelected(row);\n    }\n\n    @NonNull\n    public SelectionState getCellSelectionState(int column, int row) {\n        if (isCellSelected(column, row)) {\n            return SelectionState.SELECTED;\n        }\n        return SelectionState.UNSELECTED;\n    }\n\n    public boolean isColumnSelected(int column) {\n        return (getSelectedColumnPosition() == column && getSelectedRowPosition() ==\n                UNSELECTED_POSITION);\n    }\n\n    public boolean isColumnShadowed(int column) {\n        return (getSelectedColumnPosition() == column && getSelectedRowPosition() !=\n                UNSELECTED_POSITION) || (getSelectedColumnPosition() == UNSELECTED_POSITION &&\n                getSelectedRowPosition() != UNSELECTED_POSITION);\n    }\n\n    public boolean isAnyColumnSelected() {\n        return (getSelectedColumnPosition() != SelectionHandler.UNSELECTED_POSITION &&\n                getSelectedRowPosition() == SelectionHandler.UNSELECTED_POSITION);\n    }\n\n    @NonNull\n    public SelectionState getColumnSelectionState(int column) {\n\n        if (isColumnShadowed(column)) {\n            return SelectionState.SHADOWED;\n\n        } else if (isColumnSelected(column)) {\n            return SelectionState.SELECTED;\n\n        } else {\n            return SelectionState.UNSELECTED;\n        }\n    }\n\n    public boolean isRowSelected(int row) {\n        return (getSelectedRowPosition() == row && getSelectedColumnPosition() ==\n                UNSELECTED_POSITION);\n    }\n\n    public boolean isRowShadowed(int row) {\n        return (getSelectedRowPosition() == row && getSelectedColumnPosition() !=\n                UNSELECTED_POSITION) || (getSelectedRowPosition() == UNSELECTED_POSITION &&\n                getSelectedColumnPosition() != UNSELECTED_POSITION);\n    }\n\n    @NonNull\n    public SelectionState getRowSelectionState(int row) {\n\n        if (isRowShadowed(row)) {\n            return SelectionState.SHADOWED;\n\n        } else if (isRowSelected(row)) {\n            return SelectionState.SELECTED;\n\n        } else {\n            return SelectionState.UNSELECTED;\n        }\n    }\n\n    private void changeVisibleCellViewsBackgroundForRow(int row, boolean isSelected) {\n        int backgroundColor = mTableView.getUnSelectedColor();\n        SelectionState selectionState = SelectionState.UNSELECTED;\n\n        if (isSelected) {\n            backgroundColor = mTableView.getSelectedColor();\n            selectionState = SelectionState.SELECTED;\n        }\n\n        CellRecyclerView recyclerView = (CellRecyclerView) mCellLayoutManager.findViewByPosition\n                (row);\n\n        if (recyclerView == null) {\n            return;\n        }\n\n        changeSelectionOfRecyclerView(recyclerView, selectionState, backgroundColor);\n    }\n\n    private void changeVisibleCellViewsBackgroundForColumn(int column, boolean isSelected) {\n        int backgroundColor = mTableView.getUnSelectedColor();\n        SelectionState selectionState = SelectionState.UNSELECTED;\n\n        if (isSelected) {\n            backgroundColor = mTableView.getSelectedColor();\n            selectionState = SelectionState.SELECTED;\n        }\n\n\n        // Get visible Cell ViewHolders by Column Position\n        for (int i = mCellLayoutManager.findFirstVisibleItemPosition(); i < mCellLayoutManager\n                .findLastVisibleItemPosition() + 1; i++) {\n\n            CellRecyclerView cellRowRecyclerView = (CellRecyclerView) mCellLayoutManager\n                    .findViewByPosition(i);\n\n            AbstractViewHolder holder = (AbstractViewHolder) cellRowRecyclerView\n                    .findViewHolderForAdapterPosition(column);\n\n            if (holder != null) {\n                // Get each view container of the cell view and set unselected color.\n                holder.setBackgroundColor(backgroundColor);\n\n                // Change selection status of the view holder\n                holder.setSelected(selectionState);\n            }\n        }\n    }\n\n    public void changeRowBackgroundColorBySelectionStatus(@NonNull AbstractViewHolder viewHolder,\n                                                          @NonNull SelectionState selectionState) {\n        if (shadowEnabled && selectionState == SelectionState.SHADOWED) {\n            viewHolder.setBackgroundColor(mTableView.getShadowColor());\n\n        } else if (selectionState == SelectionState.SELECTED) {\n            viewHolder.setBackgroundColor(mTableView.getSelectedColor());\n\n        } else {\n            viewHolder.setBackgroundColor(mTableView.getUnSelectedColor());\n        }\n    }\n\n    public void changeColumnBackgroundColorBySelectionStatus(@NonNull AbstractViewHolder viewHolder,\n                                                             @NonNull SelectionState selectionState) {\n        if (shadowEnabled && selectionState == SelectionState.SHADOWED) {\n            viewHolder.setBackgroundColor(mTableView.getShadowColor());\n\n        } else if (selectionState == SelectionState.SELECTED) {\n            viewHolder.setBackgroundColor(mTableView.getSelectedColor());\n\n        } else {\n            viewHolder.setBackgroundColor(mTableView.getUnSelectedColor());\n        }\n    }\n\n    public void changeSelectionOfRecyclerView(CellRecyclerView recyclerView, @NonNull AbstractViewHolder\n            .SelectionState selectionState, @ColorInt int backgroundColor) {\n\n        LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView\n                .getLayoutManager();\n\n        for (int i = linearLayoutManager.findFirstVisibleItemPosition(); i < linearLayoutManager\n                .findLastVisibleItemPosition() + 1; i++) {\n\n            AbstractViewHolder viewHolder = (AbstractViewHolder) recyclerView\n                    .findViewHolderForAdapterPosition(i);\n\n            if (viewHolder != null) {\n                if (!mTableView.isIgnoreSelectionColors()) {\n                    // Change background color\n                    viewHolder.setBackgroundColor(backgroundColor);\n                }\n\n                // Change selection status of the view holder\n                viewHolder.setSelected(selectionState);\n            }\n        }\n    }\n\n    public void clearSelection() {\n        unselectedRowHeader();\n        unselectedCellView();\n        unselectedColumnHeader();\n    }\n\n    public void setSelectedRowPosition(int row) {\n        this.mSelectedRowPosition = row;\n    }\n\n    public void setSelectedColumnPosition(int column) {\n        this.mSelectedColumnPosition = column;\n    }\n\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/handler/VisibilityHandler.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.handler;\n\nimport android.util.Log;\nimport android.util.SparseArray;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.evrencoskun.tableview.ITableView;\nimport com.evrencoskun.tableview.adapter.AbstractTableAdapter;\nimport java.util.List;\n\n/**\n * Created by evrencoskun on 24.12.2017.\n */\n\npublic class VisibilityHandler {\n    private static final String LOG_TAG = VisibilityHandler.class.getSimpleName();\n\n    @NonNull\n    private final ITableView mTableView;\n    @NonNull\n    private SparseArray<Row> mHideRowList = new SparseArray<>();\n    @NonNull\n    private SparseArray<Column> mHideColumnList = new SparseArray<>();\n\n    public VisibilityHandler(@NonNull ITableView tableView) {\n        this.mTableView = tableView;\n    }\n\n    public void hideRow(int row) {\n        int viewRow = convertIndexToViewIndex(row, mHideRowList);\n\n        if (mHideRowList.get(row) == null) {\n            // add row the list\n            mHideRowList.put(row, getRowValueFromPosition(row));\n\n            // remove row model from adapter\n            mTableView.getAdapter().removeRow(viewRow);\n        } else {\n            Log.e(LOG_TAG, \"This row is already hidden.\");\n        }\n    }\n\n    public void showRow(int row) {\n        showRow(row, true);\n    }\n\n    private void showRow(int row, boolean removeFromList) {\n        Row hiddenRow = mHideRowList.get(row);\n\n        if (hiddenRow != null) {\n            // add row model to the adapter\n            mTableView.getAdapter().addRow(row, hiddenRow.getRowHeaderModel(),\n                    hiddenRow.getCellModelList());\n        } else {\n            Log.e(LOG_TAG, \"This row is already visible.\");\n        }\n\n        if (removeFromList) {\n            mHideRowList.remove(row);\n        }\n    }\n\n    public void clearHideRowList() {\n        mHideRowList.clear();\n    }\n\n    public void showAllHiddenRows() {\n        for (int i = 0; i < mHideRowList.size(); i++) {\n            int row = mHideRowList.keyAt(i);\n            showRow(row, false);\n        }\n\n        clearHideRowList();\n    }\n\n    public boolean isRowVisible(int row) {\n        return mHideRowList.get(row) == null;\n    }\n\n    public void hideColumn(int column) {\n        int viewColumn = convertIndexToViewIndex(column, mHideColumnList);\n\n        if (mHideColumnList.get(column) == null) {\n            // add column the list\n            mHideColumnList.put(column, getColumnValueFromPosition(column));\n\n            // remove row model from adapter\n            mTableView.getAdapter().removeColumn(viewColumn);\n        } else {\n            Log.e(LOG_TAG, \"This column is already hidden.\");\n        }\n    }\n\n    public void showColumn(int column) {\n        showColumn(column, true);\n    }\n\n    private void showColumn(int column, boolean removeFromList) {\n        Column hiddenColumn = mHideColumnList.get(column);\n\n        if (hiddenColumn != null) {\n            // add column model to the adapter\n            mTableView.getAdapter().addColumn(column, hiddenColumn.getColumnHeaderModel(),\n                    hiddenColumn.getCellModelList());\n        } else {\n            Log.e(LOG_TAG, \"This column is already visible.\");\n        }\n\n        if (removeFromList) {\n            mHideColumnList.remove(column);\n        }\n    }\n\n    public void clearHideColumnList() {\n        mHideColumnList.clear();\n    }\n\n    public void showAllHiddenColumns() {\n        for (int i = 0; i < mHideColumnList.size(); i++) {\n            int column = mHideColumnList.keyAt(i);\n            showColumn(column, false);\n        }\n\n        clearHideColumnList();\n    }\n\n    public boolean isColumnVisible(int column) {\n        return mHideColumnList.get(column) == null;\n    }\n\n\n    /**\n     * Hiding row and column process needs to consider the hidden rows or columns with a smaller\n     * index to be able hide the correct index.\n     *\n     * @param index, stands for column or row index.\n     * @param list,  stands for HideRowList or HideColumnList\n     */\n    private <T> int getSmallerHiddenCount(int index, SparseArray<T> list) {\n        int count = 0;\n        for (int i = 0; i < index && i < list.size(); i++) {\n            if (list.valueAt(i) != null) {\n                count++;\n            }\n        }\n        return count;\n    }\n\n    /**\n     * It converts model index to View index considering the previous hidden rows or columns. So,\n     * when we add or remove any item of RecyclerView, we need to view index.\n     */\n    private <T> int convertIndexToViewIndex(int index, SparseArray<T> list) {\n        return index - getSmallerHiddenCount(index, list);\n    }\n\n    static class Row {\n        private final int mYPosition;\n        @Nullable\n        private final Object mRowHeaderModel;\n        @Nullable\n        private final List<Object> mCellModelList;\n\n        public Row(int row, @Nullable Object rowHeaderModel, @Nullable List<Object> cellModelList) {\n            this.mYPosition = row;\n            this.mRowHeaderModel = rowHeaderModel;\n            this.mCellModelList = cellModelList;\n        }\n\n        public int getYPosition() {\n            return mYPosition;\n        }\n\n        @Nullable\n        public Object getRowHeaderModel() {\n            return mRowHeaderModel;\n        }\n\n        @Nullable\n        public List<Object> getCellModelList() {\n            return mCellModelList;\n        }\n\n    }\n\n    static class Column {\n        private final int mYPosition;\n        @Nullable\n        private final Object mColumnHeaderModel;\n        @NonNull\n        private final List<Object> mCellModelList;\n\n        public Column(int yPosition, @Nullable Object columnHeaderModel,\n                      @NonNull List<Object> cellModelList) {\n            this.mYPosition = yPosition;\n            this.mColumnHeaderModel = columnHeaderModel;\n            this.mCellModelList = cellModelList;\n        }\n\n        public int getYPosition() {\n            return mYPosition;\n        }\n\n        @Nullable\n        public Object getColumnHeaderModel() {\n            return mColumnHeaderModel;\n        }\n\n        @NonNull\n        public List<Object> getCellModelList() {\n            return mCellModelList;\n        }\n\n    }\n\n    @NonNull\n    private Row getRowValueFromPosition(int row) {\n        AbstractTableAdapter adapter = mTableView.getAdapter();\n        Object rowHeaderModel = adapter.getRowHeaderItem(row);\n        List<Object> cellModelList = adapter.getCellRowItems(row);\n\n        return new Row(row, rowHeaderModel, cellModelList);\n    }\n\n    @NonNull\n    private Column getColumnValueFromPosition(int column) {\n        AbstractTableAdapter adapter = mTableView.getAdapter();\n        Object columnHeaderModel = adapter.getColumnHeaderItem(column);\n        List<Object> cellModelList = adapter.getCellColumnItems(column);\n\n        return new Column(column, columnHeaderModel, cellModelList);\n    }\n\n    @NonNull\n    public SparseArray<Row> getHideRowList() {\n        return mHideRowList;\n    }\n\n    @NonNull\n    public SparseArray<Column> getHideColumnList() {\n        return mHideColumnList;\n    }\n\n    public void setHideRowList(@NonNull SparseArray<Row> rowList) {\n        this.mHideRowList = rowList;\n    }\n\n    public void setHideColumnList(@NonNull SparseArray<Column> columnList) {\n        this.mHideColumnList = columnList;\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/layoutmanager/CellLayoutManager.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.layoutmanager;\n\nimport android.content.Context;\nimport android.os.Handler;\nimport android.util.Log;\nimport android.util.SparseArray;\nimport android.util.SparseIntArray;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.evrencoskun.tableview.ITableView;\nimport com.evrencoskun.tableview.adapter.recyclerview.CellRecyclerView;\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder;\nimport com.evrencoskun.tableview.listener.scroll.HorizontalRecyclerViewListener;\nimport com.evrencoskun.tableview.util.TableViewUtils;\n\nimport static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;\n\n/**\n * Created by evrencoskun on 24/06/2017.\n */\n\npublic class CellLayoutManager extends LinearLayoutManager {\n    private static final String LOG_TAG = CellLayoutManager.class.getSimpleName();\n    private static final int IGNORE_LEFT = -99999;\n\n    @NonNull\n    private final ColumnHeaderLayoutManager mColumnHeaderLayoutManager;\n\n    @NonNull\n    private final CellRecyclerView mRowHeaderRecyclerView;\n\n    private HorizontalRecyclerViewListener mHorizontalListener;\n    @NonNull\n    private final ITableView mTableView;\n\n    @NonNull\n    private final SparseArray<SparseIntArray> mCachedWidthList = new SparseArray<>();\n    //TODO: Store a single instance for both cell and column cache width values.\n\n    private int mLastDy = 0;\n    private boolean mNeedSetLeft;\n    private boolean mNeedFit;\n\n    public CellLayoutManager(@NonNull Context context, @NonNull ITableView tableView) {\n        super(context);\n        this.mTableView = tableView;\n        this.mColumnHeaderLayoutManager = tableView.getColumnHeaderLayoutManager();\n        this.mRowHeaderRecyclerView = tableView.getRowHeaderRecyclerView();\n\n        initialize();\n    }\n\n    private void initialize() {\n        this.setOrientation(VERTICAL);\n        // Add new one\n    }\n\n    @Override\n    public void onAttachedToWindow(RecyclerView view) {\n        super.onAttachedToWindow(view);\n\n        // initialize the instances\n        if (mHorizontalListener == null) {\n            mHorizontalListener = mTableView.getHorizontalRecyclerViewListener();\n        }\n    }\n\n    @Override\n    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State\n            state) {\n        if (mRowHeaderRecyclerView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE &&\n                !mRowHeaderRecyclerView.isScrollOthers()) {\n            // CellRecyclerViews should be scrolled after the RowHeaderRecyclerView.\n            // Because it is one of the main compared criterion to make each columns fit.\n            mRowHeaderRecyclerView.scrollBy(0, dy);\n        }\n\n        int scroll = super.scrollVerticallyBy(dy, recycler, state);\n\n        // It is important to determine right position to fit all columns which are the same y pos.\n        mLastDy = dy;\n        return scroll;\n    }\n\n    @Override\n    public void onScrollStateChanged(int state) {\n        super.onScrollStateChanged(state);\n        if (state == RecyclerView.SCROLL_STATE_IDLE) {\n            // It is important to set it 0 to be able to know which direction is being scrolled\n            mLastDy = 0;\n        }\n    }\n\n    /**\n     * This method helps to fit all columns which are displayed on screen.\n     * Especially it will be called when TableView is scrolled on vertically.\n     */\n    public void fitWidthSize(boolean scrollingUp) {\n        int left = mColumnHeaderLayoutManager.getFirstItemLeft();\n        for (int i = mColumnHeaderLayoutManager.findFirstVisibleItemPosition(); i <\n                mColumnHeaderLayoutManager.findLastVisibleItemPosition() + 1; i++) {\n            left = fitSize(i, left, scrollingUp);\n        }\n\n        mNeedSetLeft = false;\n    }\n\n    /**\n     * This method helps to fit a column. it will be called when TableView is scrolled on\n     * horizontally.\n     */\n    public void fitWidthSize(int position, boolean scrollingLeft) {\n        fitSize(position, IGNORE_LEFT, false);\n\n        if (mNeedSetLeft & scrollingLeft) {\n            // Works just like invoke later of swing utils.\n            Handler handler = new Handler();\n            handler.post(() -> fitWidthSize2(true));\n        }\n    }\n\n    private int fitSize(int position, int left, boolean scrollingUp) {\n        int cellRight = -1;\n\n        int columnCacheWidth = mColumnHeaderLayoutManager.getCacheWidth(position);\n        View column = mColumnHeaderLayoutManager.findViewByPosition(position);\n\n        if (column != null) {\n            // Determine default right\n            cellRight = column.getLeft() + columnCacheWidth + 1;\n\n            if (scrollingUp) {\n                // Loop reverse order\n                for (int i = findLastVisibleItemPosition(); i >= findFirstVisibleItemPosition();\n                     i--) {\n                    cellRight = fit(position, i, left, cellRight, columnCacheWidth);\n                }\n            } else {\n                // Loop for all rows which are visible.\n                for (int j = findFirstVisibleItemPosition(); j < findLastVisibleItemPosition() +\n                        1; j++) {\n                    cellRight = fit(position, j, left, cellRight, columnCacheWidth);\n                }\n            }\n        } else {\n            Log.e(LOG_TAG, \"Warning: column couldn't found for \" + position);\n        }\n        return cellRight;\n    }\n\n    private int fit(int xPosition, int yPosition, int left, int right, int columnCachedWidth) {\n        CellRecyclerView child = (CellRecyclerView) findViewByPosition(yPosition);\n\n        if (child != null) {\n            ColumnLayoutManager childLayoutManager = (ColumnLayoutManager) child.getLayoutManager();\n\n            int cellCacheWidth = getCacheWidth(yPosition, xPosition);\n            View cell = childLayoutManager.findViewByPosition(xPosition);\n\n            // Control whether the cell needs to be fitted by column header or not.\n            if (cell != null) {\n\n                if (cellCacheWidth != columnCachedWidth || mNeedSetLeft) {\n\n                    // This is just for setting width value\n                    if (cellCacheWidth != columnCachedWidth) {\n                        cellCacheWidth = columnCachedWidth;\n                        TableViewUtils.setWidth(cell, cellCacheWidth);\n\n                        setCacheWidth(yPosition, xPosition, cellCacheWidth);\n                    }\n\n                    // Even if the cached values are same, the left & right value wouldn't change.\n                    // mNeedSetLeft & the below lines for it.\n                    if (left != IGNORE_LEFT && cell.getLeft() != left) {\n\n                        // Calculate scroll distance\n                        int scrollX = Math.max(cell.getLeft(), left) - Math.min(cell.getLeft(),\n                                left);\n\n                        // Update its left\n                        cell.setLeft(left);\n\n                        int offset = mHorizontalListener.getScrollPositionOffset();\n\n                        // It shouldn't be scroll horizontally and the problem is gotten just for\n                        // first visible item.\n                        if (offset > 0 && xPosition == childLayoutManager\n                                .findFirstVisibleItemPosition() && getCellRecyclerViewScrollState() != RecyclerView.SCROLL_STATE_IDLE) {\n\n                            int scrollPosition = mHorizontalListener.getScrollPosition();\n                            offset = mHorizontalListener.getScrollPositionOffset() + scrollX;\n\n                            // Update scroll position offset value\n                            mHorizontalListener.setScrollPositionOffset(offset);\n                            // Scroll considering to the desired value.\n                            childLayoutManager.scrollToPositionWithOffset(scrollPosition, offset);\n                        }\n                    }\n\n                    if (cell.getWidth() != cellCacheWidth) {\n                        if (left != IGNORE_LEFT) {\n                            // TODO: + 1 is for decoration item. It should be gotten from a\n                            // generic method  of layoutManager\n                            // Set right\n                            right = cell.getLeft() + cellCacheWidth + 1;\n                            cell.setRight(right);\n\n                            childLayoutManager.layoutDecoratedWithMargins(cell, cell.getLeft(),\n                                    cell.getTop(), cell.getRight(), cell.getBottom());\n                        }\n\n                        mNeedSetLeft = true;\n                    }\n                }\n            }\n        }\n        return right;\n    }\n\n    /**\n     * Alternative method of fitWidthSize().\n     * The main difference is this method works after main thread draw the ui components.\n     */\n    public void fitWidthSize2(boolean scrollingLeft) {\n        // The below line helps to change left & right value of the each column\n        // header views\n        // without using requestLayout().\n        mColumnHeaderLayoutManager.customRequestLayout();\n\n        // Get the right scroll position information from Column header RecyclerView\n        int columnHeaderScrollPosition = mTableView.getColumnHeaderRecyclerView().getScrolledX();\n        int columnHeaderOffset = mColumnHeaderLayoutManager.getFirstItemLeft();\n        int columnHeaderFirstItem = mColumnHeaderLayoutManager.findFirstVisibleItemPosition();\n\n        // Fit all visible columns widths\n        for (int i = mColumnHeaderLayoutManager.findFirstVisibleItemPosition(); i <\n                mColumnHeaderLayoutManager.findLastVisibleItemPosition() + 1; i++) {\n\n            fitSize2(i, scrollingLeft, columnHeaderScrollPosition, columnHeaderOffset,\n                    columnHeaderFirstItem);\n        }\n\n        mNeedSetLeft = false;\n    }\n\n    /**\n     * Alternative method of fitWidthSize().\n     * The main difference is this method works after main thread draw the ui components.\n     */\n    public void fitWidthSize2(int position, boolean scrollingLeft) {\n        // The below line helps to change left & right value of the each column\n        // header views\n        // without using requestLayout().\n        mColumnHeaderLayoutManager.customRequestLayout();\n\n        // Get the right scroll position information from Column header RecyclerView\n        int columnHeaderScrollPosition = mTableView.getColumnHeaderRecyclerView().getScrolledX();\n        int columnHeaderOffset = mColumnHeaderLayoutManager.getFirstItemLeft();\n        int columnHeaderFirstItem = mColumnHeaderLayoutManager.findFirstVisibleItemPosition();\n\n        // Fit all visible columns widths\n        fitSize2(position, scrollingLeft, columnHeaderScrollPosition, columnHeaderOffset,\n                columnHeaderFirstItem);\n\n\n        mNeedSetLeft = false;\n    }\n\n    private void fitSize2(int position, boolean scrollingLeft, int columnHeaderScrollPosition,\n                          int columnHeaderOffset, int columnHeaderFirstItem) {\n        int columnCacheWidth = mColumnHeaderLayoutManager.getCacheWidth(position);\n        View column = mColumnHeaderLayoutManager.findViewByPosition(position);\n\n        if (column != null) {\n            // Loop for all rows which are visible.\n            for (int j = findFirstVisibleItemPosition(); j < findLastVisibleItemPosition() + 1;\n                 j++) {\n\n                // Get CellRowRecyclerView\n                CellRecyclerView child = (CellRecyclerView) findViewByPosition(j);\n\n                if (child != null) {\n                    ColumnLayoutManager childLayoutManager = (ColumnLayoutManager) child\n                            .getLayoutManager();\n\n                    // Checking Scroll position is necessary. Because, even if they have same width\n                    // values, their scroll positions can be different.\n                    if (!scrollingLeft && columnHeaderScrollPosition != child.getScrolledX()) {\n\n                        // Column Header RecyclerView has the right scroll position. So,\n                        // considering it\n                        childLayoutManager.scrollToPositionWithOffset(columnHeaderFirstItem,\n                                columnHeaderOffset);\n                    }\n\n                    if (childLayoutManager != null) {\n                        fit2(position, j, columnCacheWidth, column, childLayoutManager);\n                    }\n                }\n            }\n        }\n    }\n\n    private void fit2(int xPosition, int yPosition, int columnCachedWidth, @NonNull View column,\n                      @NonNull ColumnLayoutManager childLayoutManager) {\n        int cellCacheWidth = getCacheWidth(yPosition, xPosition);\n        View cell = childLayoutManager.findViewByPosition(xPosition);\n\n        // Control whether the cell needs to be fitted by column header or not.\n        if (cell != null) {\n\n            if (cellCacheWidth != columnCachedWidth || mNeedSetLeft) {\n\n                // This is just for setting width value\n                if (cellCacheWidth != columnCachedWidth) {\n                    cellCacheWidth = columnCachedWidth;\n                    TableViewUtils.setWidth(cell, cellCacheWidth);\n\n                    setCacheWidth(yPosition, xPosition, cellCacheWidth);\n                }\n\n                // The left & right values of Column header can be considered. Because this\n                // method will be worked\n                // after drawing process of main thread.\n                if (column.getLeft() != cell.getLeft() || column.getRight() != cell.getRight()) {\n                    // TODO: + 1 is for decoration item. It should be gotten from a generic\n                    // method  of layoutManager\n                    // Set right & left values\n                    cell.setLeft(column.getLeft());\n                    cell.setRight(column.getRight() + 1);\n                    childLayoutManager.layoutDecoratedWithMargins(cell, cell.getLeft(), cell\n                            .getTop(), cell.getRight(), cell.getBottom());\n\n                    mNeedSetLeft = true;\n                }\n            }\n        }\n    }\n\n    public boolean shouldFitColumns(int yPosition) {\n\n        // Scrolling horizontally\n        if (getCellRecyclerViewScrollState() == RecyclerView.SCROLL_STATE_IDLE) {\n\n            int lastVisiblePosition = findLastVisibleItemPosition();\n            CellRecyclerView lastCellRecyclerView = (CellRecyclerView) findViewByPosition\n                    (lastVisiblePosition);\n\n            if (lastCellRecyclerView != null) {\n                if (yPosition == lastVisiblePosition) {\n                    return true;\n                } else if (lastCellRecyclerView.isScrollOthers() && yPosition ==\n                        lastVisiblePosition - 1) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public void measureChildWithMargins(@NonNull View child, int widthUsed, int heightUsed) {\n        super.measureChildWithMargins(child, widthUsed, heightUsed);\n\n        // If has fixed width is true, than calculation of the column width is not necessary.\n        if (mTableView.hasFixedWidth()) {\n            return;\n        }\n\n        int position = getPosition(child);\n\n        ColumnLayoutManager childLayoutManager = (ColumnLayoutManager) ((CellRecyclerView) child)\n                .getLayoutManager();\n\n        // the below codes should be worked when it is scrolling vertically\n        if (getCellRecyclerViewScrollState() != RecyclerView.SCROLL_STATE_IDLE) {\n            if (childLayoutManager.isNeedFit()) {\n\n                // Scrolling up\n                if (mLastDy < 0) {\n                    Log.e(LOG_TAG, position + \" fitWidthSize all vertically up\");\n                    fitWidthSize(true);\n                } else {\n                    // Scrolling down\n                    Log.e(LOG_TAG, position + \" fitWidthSize all vertically down\");\n                    fitWidthSize(false);\n                }\n                // all columns have been fitted.\n                childLayoutManager.clearNeedFit();\n            }\n\n            // Set the right initialPrefetch size to improve performance\n            childLayoutManager.setInitialPrefetchItemCount(childLayoutManager.getChildCount());\n\n            // That means,populating for the first time like fetching all data to display.\n            // It shouldn't be worked when it is scrolling horizontally .\"getLastDx() == 0\"\n            // control for it.\n        } else if (childLayoutManager.getLastDx() == 0 && getCellRecyclerViewScrollState() ==\n                RecyclerView.SCROLL_STATE_IDLE) {\n\n            if (childLayoutManager.isNeedFit()) {\n                mNeedFit = true;\n\n                // all columns have been fitted.\n                childLayoutManager.clearNeedFit();\n            }\n\n            if (mNeedFit) {\n                // for the first time to populate adapter\n                if (mTableView.getRowHeaderLayoutManager().findLastVisibleItemPosition() == position) {\n\n                    fitWidthSize2(false);\n                    Log.e(LOG_TAG, position + \" fitWidthSize populating data for the first time\");\n\n                    mNeedFit = false;\n                }\n            }\n        }\n    }\n\n    @NonNull\n    public AbstractViewHolder[] getVisibleCellViewsByColumnPosition(int xPosition) {\n        int visibleChildCount = findLastVisibleItemPosition() - findFirstVisibleItemPosition() + 1;\n        int index = 0;\n        AbstractViewHolder[] viewHolders = new AbstractViewHolder[visibleChildCount];\n        for (int i = findFirstVisibleItemPosition(); i < findLastVisibleItemPosition() + 1; i++) {\n            CellRecyclerView cellRowRecyclerView = (CellRecyclerView) findViewByPosition(i);\n\n            AbstractViewHolder holder = (AbstractViewHolder) cellRowRecyclerView\n                    .findViewHolderForAdapterPosition(xPosition);\n\n            viewHolders[index] = holder;\n\n            index++;\n        }\n        return viewHolders;\n    }\n\n    @Nullable\n    public AbstractViewHolder getCellViewHolder(int xPosition, int yPosition) {\n        CellRecyclerView cellRowRecyclerView = (CellRecyclerView) findViewByPosition(yPosition);\n\n        if (cellRowRecyclerView != null) {\n            return (AbstractViewHolder) cellRowRecyclerView.findViewHolderForAdapterPosition\n                    (xPosition);\n        }\n        return null;\n    }\n\n    public void remeasureAllChild() {\n        // TODO: the below code causes requestLayout() improperly called by com.evrencoskun.tableview.adapter\n\n        for (int j = 0; j < getChildCount(); j++) {\n            CellRecyclerView recyclerView = (CellRecyclerView) getChildAt(j);\n\n            recyclerView.getLayoutParams().width = WRAP_CONTENT;\n            recyclerView.requestLayout();\n        }\n    }\n\n    /**\n     * Allows to set cache width value for single cell item.\n     */\n    public void setCacheWidth(int row, int column, int width) {\n        SparseIntArray cellRowCache = mCachedWidthList.get(row);\n        if (cellRowCache == null) {\n            cellRowCache = new SparseIntArray();\n        }\n\n        cellRowCache.put(column, width);\n        mCachedWidthList.put(row, cellRowCache);\n    }\n\n    /**\n     * Allows to set cache width value for all cell items that is located on column position.\n     */\n    public void setCacheWidth(int column, int width) {\n        for (int i = 0; i < mRowHeaderRecyclerView.getAdapter().getItemCount(); i++) {\n            // set cache width for single cell item.\n            setCacheWidth(i, column, width);\n        }\n    }\n\n    public int getCacheWidth(int row, int column) {\n        SparseIntArray cellRowCaches = mCachedWidthList.get(row);\n        if (cellRowCaches != null) {\n            return cellRowCaches.get(column, -1);\n        }\n        return -1;\n    }\n\n    /**\n     * Clears the widths which have been calculated and reused.\n     */\n    public void clearCachedWidths() {\n        mCachedWidthList.clear();\n    }\n\n    @NonNull\n    public CellRecyclerView[] getVisibleCellRowRecyclerViews() {\n        int length = findLastVisibleItemPosition() - findFirstVisibleItemPosition() + 1;\n        CellRecyclerView[] recyclerViews = new CellRecyclerView[length];\n\n        int index = 0;\n        for (int i = findFirstVisibleItemPosition(); i < findLastVisibleItemPosition() + 1; i++) {\n            recyclerViews[index] = (CellRecyclerView) findViewByPosition(i);\n            index++;\n        }\n\n        return recyclerViews;\n    }\n\n    private int getCellRecyclerViewScrollState() {\n        return mTableView.getCellRecyclerView().getScrollState();\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/layoutmanager/ColumnHeaderLayoutManager.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.layoutmanager;\n\nimport android.content.Context;\nimport android.util.SparseIntArray;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.recyclerview.widget.LinearLayoutManager;\n\nimport com.evrencoskun.tableview.ITableView;\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder;\nimport com.evrencoskun.tableview.util.TableViewUtils;\n\n/**\n * Created by evrencoskun on 30/07/2017.\n */\n\npublic class ColumnHeaderLayoutManager extends LinearLayoutManager {\n    //private SparseArray<Integer> mCachedWidthList;\n    @NonNull\n    private final SparseIntArray mCachedWidthList = new SparseIntArray();\n    @NonNull\n    private final ITableView mTableView;\n\n    public ColumnHeaderLayoutManager(@NonNull Context context, @NonNull ITableView tableView) {\n        super(context);\n        mTableView = tableView;\n\n        this.setOrientation(ColumnHeaderLayoutManager.HORIZONTAL);\n    }\n\n    @Override\n    public void measureChildWithMargins(@NonNull View child, int widthUsed, int heightUsed) {\n        super.measureChildWithMargins(child, widthUsed, heightUsed);\n\n        // If has fixed width is true, than calculation of the column width is not necessary.\n        if (mTableView.hasFixedWidth()) {\n            return;\n        }\n\n        measureChild(child, widthUsed, heightUsed);\n    }\n\n    @Override\n    public void measureChild(@NonNull View child, int widthUsed, int heightUsed) {\n        // If has fixed width is true, than calculation of the column width is not necessary.\n        if (mTableView.hasFixedWidth()) {\n            super.measureChild(child, widthUsed, heightUsed);\n            return;\n        }\n\n        int position = getPosition(child);\n        int cacheWidth = getCacheWidth(position);\n\n        // If the width value of the cell has already calculated, then set the value\n        if (cacheWidth != -1) {\n            TableViewUtils.setWidth(child, cacheWidth);\n        } else {\n            super.measureChild(child, widthUsed, heightUsed);\n        }\n    }\n\n    public void setCacheWidth(int position, int width) {\n        mCachedWidthList.put(position, width);\n    }\n\n    public int getCacheWidth(int position) {\n        return mCachedWidthList.get(position, -1);\n    }\n\n    public int getFirstItemLeft() {\n        View firstColumnHeader = findViewByPosition(findFirstVisibleItemPosition());\n        return firstColumnHeader.getLeft();\n    }\n\n    /**\n     * Helps to recalculate the width value of the cell that is located in given position.\n     */\n    public void removeCachedWidth(int position) {\n        mCachedWidthList.removeAt(position);\n    }\n\n    /**\n     * Clears the widths which have been calculated and reused.\n     */\n    public void clearCachedWidths() {\n        mCachedWidthList.clear();\n    }\n\n    public void customRequestLayout() {\n        int left = getFirstItemLeft();\n        int right;\n        for (int i = findFirstVisibleItemPosition(); i < findLastVisibleItemPosition() + 1; i++) {\n\n            // Column headers should have been already calculated.\n            right = left + getCacheWidth(i);\n\n            View columnHeader = findViewByPosition(i);\n            columnHeader.setLeft(left);\n            columnHeader.setRight(right);\n\n            layoutDecoratedWithMargins(columnHeader, columnHeader.getLeft(), columnHeader.getTop\n                    (), columnHeader.getRight(), columnHeader.getBottom());\n\n            // + 1 is for decoration item.\n            left = right + 1;\n        }\n    }\n\n    @NonNull\n    public AbstractViewHolder[] getVisibleViewHolders() {\n        int visibleChildCount = findLastVisibleItemPosition() - findFirstVisibleItemPosition() + 1;\n        int index = 0;\n\n        AbstractViewHolder[] views = new AbstractViewHolder[visibleChildCount];\n        for (int i = findFirstVisibleItemPosition(); i < findLastVisibleItemPosition() + 1; i++) {\n\n            views[index] = (AbstractViewHolder) mTableView.getColumnHeaderRecyclerView()\n                    .findViewHolderForAdapterPosition(i);\n\n            index++;\n        }\n        return views;\n    }\n\n    @Nullable\n    public AbstractViewHolder getViewHolder(int xPosition) {\n        return (AbstractViewHolder) mTableView.getColumnHeaderRecyclerView()\n                .findViewHolderForAdapterPosition(xPosition);\n    }\n\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/layoutmanager/ColumnLayoutManager.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.layoutmanager;\n\nimport android.content.Context;\nimport android.util.Log;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.evrencoskun.tableview.ITableView;\nimport com.evrencoskun.tableview.adapter.recyclerview.CellRecyclerView;\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder;\nimport com.evrencoskun.tableview.util.TableViewUtils;\n\n/**\n * Created by evrencoskun on 10/06/2017.\n */\n\npublic class ColumnLayoutManager extends LinearLayoutManager {\n    private static final String LOG_TAG = ColumnLayoutManager.class.getSimpleName();\n\n    @NonNull\n    private final ITableView mTableView;\n    private CellRecyclerView mCellRowRecyclerView;\n    @NonNull\n    private final CellRecyclerView mColumnHeaderRecyclerView;\n    @NonNull\n    private final ColumnHeaderLayoutManager mColumnHeaderLayoutManager;\n    @NonNull\n    private final CellLayoutManager mCellLayoutManager;\n\n    private boolean mNeedFitForVerticalScroll, mNeedFitForHorizontalScroll;\n    private int mLastDx = 0;\n    private int mYPosition;\n\n    public ColumnLayoutManager(@NonNull Context context, @NonNull ITableView tableView) {\n        super(context);\n        this.mTableView = tableView;\n        this.mColumnHeaderRecyclerView = mTableView.getColumnHeaderRecyclerView();\n        this.mColumnHeaderLayoutManager = mTableView.getColumnHeaderLayoutManager();\n        this.mCellLayoutManager = mTableView.getCellLayoutManager();\n\n        // Set default orientation\n        this.setOrientation(ColumnLayoutManager.HORIZONTAL);\n\n        //If you are using a RecyclerView.RecycledViewPool, it might be a good idea to set this\n        // flag to true so that views will be available to other RecyclerViews immediately.\n        this.setRecycleChildrenOnDetach(true);\n    }\n\n    @Override\n    public void onAttachedToWindow(RecyclerView view) {\n        super.onAttachedToWindow(view);\n        mCellRowRecyclerView = (CellRecyclerView) view;\n        mYPosition = getRowPosition();\n    }\n\n    @Override\n    public void measureChildWithMargins(@NonNull View child, int widthUsed, int heightUsed) {\n        super.measureChildWithMargins(child, widthUsed, heightUsed);\n\n        // If has fixed width is true, than calculation of the column width is not necessary.\n        if (mTableView.hasFixedWidth()) {\n            return;\n        }\n\n        measureChild(child, widthUsed, heightUsed);\n    }\n\n    @Override\n    public void measureChild(@NonNull View child, int widthUsed, int heightUsed) {\n\n        int columnPosition = getPosition(child);\n\n        // Get cached width size of column and cell\n        int cacheWidth = mCellLayoutManager.getCacheWidth(mYPosition, columnPosition);\n        int columnCacheWidth = mColumnHeaderLayoutManager.getCacheWidth(columnPosition);\n\n        // Already each of them is same width size.\n        if (cacheWidth != -1 && cacheWidth == columnCacheWidth) {\n            // Control whether we need to set width or not.\n            if (child.getMeasuredWidth() != cacheWidth) {\n                TableViewUtils.setWidth(child, cacheWidth);\n            }\n        } else {\n            View columnHeaderChild = mColumnHeaderLayoutManager.findViewByPosition(columnPosition);\n            if (columnHeaderChild == null) {\n                return;\n            }\n\n            // Need to calculate which one has the broadest width ?\n            fitWidthSize(child, mYPosition, columnPosition, cacheWidth, columnCacheWidth,\n                    columnHeaderChild);\n        }\n\n        // Control all of the rows which has same column position.\n        if (shouldFitColumns(columnPosition, mYPosition)) {\n            if (mLastDx < 0) {\n                Log.e(LOG_TAG, \"x: \" + columnPosition + \" y: \" + mYPosition + \" fitWidthSize \" +\n                        \"left side \");\n                mCellLayoutManager.fitWidthSize(columnPosition, true);\n            } else {\n                mCellLayoutManager.fitWidthSize(columnPosition, false);\n                Log.e(LOG_TAG, \"x: \" + columnPosition + \" y: \" + mYPosition + \" fitWidthSize \" +\n                        \"right side\");\n            }\n            mNeedFitForVerticalScroll = false;\n        }\n\n        // It need to be cleared to prevent unnecessary calculation.\n        mNeedFitForHorizontalScroll = false;\n    }\n\n    private void fitWidthSize(@NonNull View child, int row, int column, int cellWidth, int\n            columnHeaderWidth, @NonNull View columnHeaderChild) {\n\n        if (cellWidth == -1) {\n            // Alternatively, TableViewUtils.getWidth(child);\n            cellWidth = child.getMeasuredWidth();\n        }\n\n        if (columnHeaderWidth == -1) {\n            // Alternatively, TableViewUtils.getWidth(columnHeaderChild)\n            columnHeaderWidth = columnHeaderChild.getMeasuredWidth();\n        }\n\n        if (cellWidth != 0) {\n\n            if (columnHeaderWidth > cellWidth) {\n                cellWidth = columnHeaderWidth;\n\n            } else if (cellWidth > columnHeaderWidth) {\n                columnHeaderWidth = cellWidth;\n            }\n\n            // Control whether column header needs to be change interns of width\n            if (columnHeaderWidth != columnHeaderChild.getWidth()) {\n                TableViewUtils.setWidth(columnHeaderChild, columnHeaderWidth);\n                mNeedFitForVerticalScroll = true;\n                mNeedFitForHorizontalScroll = true;\n            }\n\n            // Set the value to cache it for column header.\n            mColumnHeaderLayoutManager.setCacheWidth(column, columnHeaderWidth);\n        }\n\n\n        // Set the width value to cache it for cell .\n        TableViewUtils.setWidth(child, cellWidth);\n        mCellLayoutManager.setCacheWidth(row, column, cellWidth);\n    }\n\n    private boolean shouldFitColumns(int xPosition, int yPosition) {\n        if (mNeedFitForHorizontalScroll) {\n            if (!mCellRowRecyclerView.isScrollOthers() && mCellLayoutManager.shouldFitColumns\n                    (yPosition)) {\n                if (mLastDx > 0) {\n                    int last = findLastVisibleItemPosition();\n                    //Log.e(LOG_TAG, \"Warning: findFirstVisibleItemPosition is \" + last);\n                    return xPosition == last;\n                } else if (mLastDx < 0) {\n                    int first = findFirstVisibleItemPosition();\n                    //Log.e(LOG_TAG, \"Warning: findFirstVisibleItemPosition is \" + first);\n                    return xPosition == first;\n                }\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State\n            state) {\n        if (mColumnHeaderRecyclerView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE &&\n                mCellRowRecyclerView.isScrollOthers()) {\n            // Every CellRowRecyclerViews should be scrolled after the ColumnHeaderRecyclerView.\n            // Because it is the main compared one to make each columns fit.\n            mColumnHeaderRecyclerView.scrollBy(dx, 0);\n        }\n        // It is important to determine the next attached view to fit all columns\n        mLastDx = dx;\n\n        // Set the right initialPrefetch size to improve performance\n        this.setInitialPrefetchItemCount(2);\n\n        return super.scrollHorizontallyBy(dx, recycler, state);\n    }\n\n    private int getRowPosition() {\n        return mCellLayoutManager.getPosition(mCellRowRecyclerView);\n    }\n\n    public int getLastDx() {\n        return mLastDx;\n    }\n\n    public boolean isNeedFit() {\n        return mNeedFitForVerticalScroll;\n    }\n\n    public void clearNeedFit() {\n        mNeedFitForVerticalScroll = false;\n    }\n\n    @NonNull\n    public AbstractViewHolder[] getVisibleViewHolders() {\n        int visibleChildCount = findLastVisibleItemPosition() - findFirstVisibleItemPosition() + 1;\n        int index = 0;\n\n        AbstractViewHolder[] views = new AbstractViewHolder[visibleChildCount];\n        for (int i = findFirstVisibleItemPosition(); i < findLastVisibleItemPosition() + 1; i++) {\n\n            views[index] = (AbstractViewHolder) mCellRowRecyclerView\n                    .findViewHolderForAdapterPosition(i);\n\n            index++;\n        }\n        return views;\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/listener/ITableViewListener.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.listener;\n\nimport androidx.annotation.NonNull;\nimport androidx.recyclerview.widget.RecyclerView;\n\n/**\n * Created by evrencoskun on 20/09/2017.\n */\n\npublic interface ITableViewListener {\n\n    void onCellClicked(@NonNull RecyclerView.ViewHolder cellView, int column, int\n            row);\n\n    void onCellDoubleClicked(@NonNull RecyclerView.ViewHolder cellView, int column, int\n            row);\n\n    void onCellLongPressed(@NonNull RecyclerView.ViewHolder cellView, int column, int\n            row);\n\n    void onColumnHeaderClicked(@NonNull RecyclerView.ViewHolder columnHeaderView, int\n            column);\n\n    void onColumnHeaderDoubleClicked(@NonNull RecyclerView.ViewHolder columnHeaderView, int\n            column);\n\n    void onColumnHeaderLongPressed(@NonNull RecyclerView.ViewHolder columnHeaderView, int\n            column);\n\n    void onRowHeaderClicked(@NonNull RecyclerView.ViewHolder rowHeaderView, int row);\n\n    void onRowHeaderDoubleClicked(@NonNull RecyclerView.ViewHolder rowHeaderView, int row);\n\n    void onRowHeaderLongPressed(@NonNull RecyclerView.ViewHolder rowHeaderView, int\n            row);\n\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/listener/SimpleTableViewListener.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.listener;\n\nimport androidx.annotation.NonNull;\nimport androidx.recyclerview.widget.RecyclerView;\n\n/**\n * Convenience class to extend when you are only interested in a subset of events of {@link ITableViewListener}.\n */\npublic abstract class SimpleTableViewListener implements ITableViewListener {\n\t@Override\n\tpublic void onCellClicked(@NonNull RecyclerView.ViewHolder cellView, int column, int row) {\n\t}\n\n\t@Override\n\tpublic void onCellDoubleClicked(@NonNull RecyclerView.ViewHolder cellView, int column, int row) {\n\t}\n\n\t@Override\n\tpublic void onCellLongPressed(@NonNull RecyclerView.ViewHolder cellView, int column, int row) {\n\t}\n\n\t@Override\n\tpublic void onColumnHeaderClicked(@NonNull RecyclerView.ViewHolder columnHeaderView, int column) {\n\t}\n\n\t@Override\n\tpublic void onColumnHeaderDoubleClicked(@NonNull RecyclerView.ViewHolder columnHeaderView, int column) {\n\t}\n\n\t@Override\n\tpublic void onColumnHeaderLongPressed(@NonNull RecyclerView.ViewHolder columnHeaderView, int column) {\n\t}\n\n\t@Override\n\tpublic void onRowHeaderClicked(@NonNull RecyclerView.ViewHolder rowHeaderView, int row) {\n\t}\n\n\t@Override\n\tpublic void onRowHeaderDoubleClicked(@NonNull RecyclerView.ViewHolder rowHeaderView, int row) {\n\t}\n\n\t@Override\n\tpublic void onRowHeaderLongPressed(@NonNull RecyclerView.ViewHolder rowHeaderView, int row) {\n\t}\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/listener/TableViewLayoutChangeListener.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.listener;\n\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\n\nimport com.evrencoskun.tableview.ITableView;\nimport com.evrencoskun.tableview.adapter.recyclerview.CellRecyclerView;\nimport com.evrencoskun.tableview.layoutmanager.CellLayoutManager;\n\nimport static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;\n\n/**\n * Created by evrencoskun on 21.01.2018.\n */\n\npublic class TableViewLayoutChangeListener implements View.OnLayoutChangeListener {\n    @NonNull\n    private final CellRecyclerView mCellRecyclerView;\n    @NonNull\n    private final CellRecyclerView mColumnHeaderRecyclerView;\n    @NonNull\n    private final CellLayoutManager mCellLayoutManager;\n\n    public TableViewLayoutChangeListener(@NonNull ITableView tableView) {\n        this.mCellRecyclerView = tableView.getCellRecyclerView();\n        this.mColumnHeaderRecyclerView = tableView.getColumnHeaderRecyclerView();\n        this.mCellLayoutManager = tableView.getCellLayoutManager();\n    }\n\n    @Override\n    public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int\n            oldTop, int oldRight, int oldBottom) {\n\n        if (v.isShown() && (right - left) != (oldRight - oldLeft)) {\n\n            // Control who need the remeasure\n            if (mColumnHeaderRecyclerView.getWidth() > mCellRecyclerView.getWidth()) {\n                // Remeasure all nested CellRow recyclerViews\n                mCellLayoutManager.remeasureAllChild();\n\n            } else if (mCellRecyclerView.getWidth() > mColumnHeaderRecyclerView.getWidth()) {\n\n                // It seems Column Header is needed.\n                mColumnHeaderRecyclerView.getLayoutParams().width = WRAP_CONTENT;\n                mColumnHeaderRecyclerView.requestLayout();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/listener/itemclick/AbstractItemClickListener.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.listener.itemclick;\n\nimport android.view.GestureDetector;\nimport android.view.MotionEvent;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.evrencoskun.tableview.ITableView;\nimport com.evrencoskun.tableview.adapter.recyclerview.CellRecyclerView;\nimport com.evrencoskun.tableview.handler.SelectionHandler;\nimport com.evrencoskun.tableview.listener.ITableViewListener;\n\n/**\n * Created by evrencoskun on 22.11.2017.\n */\n\npublic abstract class AbstractItemClickListener implements RecyclerView.OnItemTouchListener {\n    private ITableViewListener mListener;\n    @NonNull\n    protected GestureDetector mGestureDetector;\n    @NonNull\n    protected CellRecyclerView mRecyclerView;\n    @NonNull\n    protected SelectionHandler mSelectionHandler;\n    @NonNull\n    protected ITableView mTableView;\n\n    public AbstractItemClickListener(@NonNull CellRecyclerView recyclerView, @NonNull ITableView tableView) {\n        this.mRecyclerView = recyclerView;\n        this.mTableView = tableView;\n        this.mSelectionHandler = tableView.getSelectionHandler();\n\n        mGestureDetector = new GestureDetector(mRecyclerView.getContext(), new GestureDetector\n                .SimpleOnGestureListener() {\n\n            @Nullable\n            MotionEvent start;\n\n            @Override\n            public boolean onSingleTapUp(MotionEvent e) {\n                return true;\n            }\n\n            @Override\n            public boolean onSingleTapConfirmed(MotionEvent e) {\n                return clickAction(mRecyclerView, e);\n            }\n\n            @Override\n            public boolean onDoubleTap(MotionEvent e) {\n                return doubleClickAction(e);\n            }\n\n            @Override\n            public boolean onDown(MotionEvent e) {\n                start = e;\n                return false;\n            }\n\n            @Override\n            public void onLongPress(MotionEvent e) {\n                // Check distance to prevent scroll to trigger the event\n                if (start != null && Math.abs(start.getRawX() - e.getRawX()) < 20 && Math.abs\n                        (start.getRawY() - e.getRawY()) < 20) {\n                    longPressAction(e);\n                }\n            }\n        });\n    }\n\n    @Override\n    public boolean onInterceptTouchEvent(@NonNull RecyclerView view, @NonNull MotionEvent e) {\n        mGestureDetector.onTouchEvent(e);\n        // Return false intentionally\n        return false;\n    }\n\n    @Override\n    public void onTouchEvent(@NonNull RecyclerView view, @NonNull MotionEvent motionEvent) {\n    }\n\n    @Override\n    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {\n    }\n\n    @NonNull\n    protected ITableViewListener getTableViewListener() {\n        if (mListener == null) {\n            mListener = mTableView.getTableViewListener();\n        }\n        return mListener;\n    }\n\n    abstract protected boolean clickAction(@NonNull RecyclerView view, @NonNull MotionEvent e);\n\n    abstract protected void longPressAction(@NonNull MotionEvent e);\n\n    abstract protected boolean doubleClickAction(@NonNull MotionEvent e);\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/listener/itemclick/CellRecyclerViewItemClickListener.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.listener.itemclick;\n\nimport android.view.MotionEvent;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.evrencoskun.tableview.ITableView;\nimport com.evrencoskun.tableview.adapter.recyclerview.CellRecyclerView;\nimport com.evrencoskun.tableview.adapter.recyclerview.CellRowRecyclerViewAdapter;\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder;\n\n/**\n * Created by evrencoskun on 26/09/2017.\n */\n\npublic class CellRecyclerViewItemClickListener extends AbstractItemClickListener {\n    @NonNull\n    private final CellRecyclerView mCellRecyclerView;\n\n    public CellRecyclerViewItemClickListener(@NonNull CellRecyclerView recyclerView, @NonNull ITableView tableView) {\n        super(recyclerView, tableView);\n        this.mCellRecyclerView = tableView.getCellRecyclerView();\n    }\n\n    @Override\n    protected boolean clickAction(@NonNull RecyclerView view, @NonNull MotionEvent e) {\n        // Get interacted view from x,y coordinate.\n        View childView = view.findChildViewUnder(e.getX(), e.getY());\n\n        if (childView != null) {\n            // Find the view holder\n            AbstractViewHolder holder = (AbstractViewHolder) mRecyclerView.getChildViewHolder\n                    (childView);\n\n            // Get y position from adapter\n            CellRowRecyclerViewAdapter adapter = (CellRowRecyclerViewAdapter) mRecyclerView\n                    .getAdapter();\n\n            int column = holder.getBindingAdapterPosition();\n            int row = adapter.getYPosition();\n\n            // Control to ignore selection color\n            if (!mTableView.isIgnoreSelectionColors()) {\n                mSelectionHandler.setSelectedCellPositions(holder, column, row);\n            }\n\n            // Call ITableView listener for item click\n            getTableViewListener().onCellClicked(holder, column, row);\n\n            return true;\n        }\n        return false;\n    }\n\n    @Override\n    protected void longPressAction(@NonNull MotionEvent e) {\n        // Consume the action for the time when either the cell row recyclerView or\n        // the cell recyclerView is scrolling.\n        if ((mRecyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) ||\n                (mCellRecyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE)) {\n            return;\n        }\n\n        // Get interacted view from x,y coordinate.\n        View child = mRecyclerView.findChildViewUnder(e.getX(), e.getY());\n\n        if (child != null) {\n            // Find the view holder\n            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(child);\n\n            // Get y position from adapter\n            CellRowRecyclerViewAdapter adapter = (CellRowRecyclerViewAdapter) mRecyclerView\n                    .getAdapter();\n\n            // Call ITableView listener for long click\n            getTableViewListener().onCellLongPressed(holder, holder.getBindingAdapterPosition(),\n                    adapter.getYPosition());\n        }\n    }\n\n    @Override\n    protected boolean doubleClickAction(@NonNull MotionEvent e) {\n        // Get interacted view from x,y coordinate.\n        View childView = mRecyclerView.findChildViewUnder(e.getX(), e.getY());\n\n        if (childView != null) {\n            // Find the view holder\n            AbstractViewHolder holder = (AbstractViewHolder) mRecyclerView.getChildViewHolder\n                    (childView);\n\n            // Get y position from adapter\n            CellRowRecyclerViewAdapter adapter = (CellRowRecyclerViewAdapter) mRecyclerView\n                    .getAdapter();\n\n            int column = holder.getBindingAdapterPosition();\n            int row = adapter.getYPosition();\n\n            // Control to ignore selection color\n            if (!mTableView.isIgnoreSelectionColors()) {\n                mSelectionHandler.setSelectedCellPositions(holder, column, row);\n            }\n\n            // Call ITableView listener for item click\n            getTableViewListener().onCellDoubleClicked(holder, column, row);\n\n            return true;\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/listener/itemclick/ColumnHeaderRecyclerViewItemClickListener.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.listener.itemclick;\n\nimport android.view.MotionEvent;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.evrencoskun.tableview.ITableView;\nimport com.evrencoskun.tableview.adapter.recyclerview.CellRecyclerView;\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder;\n\n/**\n * Created by evrencoskun on 26/09/2017.\n */\n\npublic class ColumnHeaderRecyclerViewItemClickListener extends AbstractItemClickListener {\n\n    public ColumnHeaderRecyclerViewItemClickListener(@NonNull CellRecyclerView recyclerView, @NonNull ITableView\n            tableView) {\n        super(recyclerView, tableView);\n\n    }\n\n    @Override\n    protected boolean clickAction(@NonNull RecyclerView view, @NonNull MotionEvent e) {\n        // Get interacted view from x,y coordinate.\n        View childView = view.findChildViewUnder(e.getX(), e.getY());\n\n        if (childView != null) {\n            // Find the view holder\n            AbstractViewHolder holder = (AbstractViewHolder) mRecyclerView.getChildViewHolder\n                    (childView);\n\n            int column = holder.getBindingAdapterPosition();\n\n            // Control to ignore selection color\n            if (!mTableView.isIgnoreSelectionColors()) {\n                mSelectionHandler.setSelectedColumnPosition(holder, column);\n            }\n\n            // Call ITableView listener for item click\n            getTableViewListener().onColumnHeaderClicked(holder, column);\n\n            return true;\n        }\n        return false;\n    }\n\n    protected void longPressAction(@NonNull MotionEvent e) {\n        // Consume the action for the time when the recyclerView is scrolling.\n        if (mRecyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {\n            return;\n        }\n\n        // Get interacted view from x,y coordinate.\n        View child = mRecyclerView.findChildViewUnder(e.getX(), e.getY());\n\n        if (child != null) {\n            // Find the view holder\n            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(child);\n\n            // Call ITableView listener for long click\n            getTableViewListener().onColumnHeaderLongPressed(holder, holder.getBindingAdapterPosition());\n        }\n    }\n\n    @Override\n    protected boolean doubleClickAction(@NonNull MotionEvent e) {\n        // Get interacted view from x,y coordinate.\n        View childView = mRecyclerView.findChildViewUnder(e.getX(), e.getY());\n\n        if (childView != null) {\n            // Find the view holder\n            AbstractViewHolder holder = (AbstractViewHolder) mRecyclerView.getChildViewHolder\n                    (childView);\n\n            int column = holder.getBindingAdapterPosition();\n\n            // Control to ignore selection color\n            if (!mTableView.isIgnoreSelectionColors()) {\n                mSelectionHandler.setSelectedColumnPosition(holder, column);\n            }\n\n            // Call ITableView listener for item click\n            getTableViewListener().onColumnHeaderDoubleClicked(holder, column);\n\n            return true;\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/listener/itemclick/RowHeaderRecyclerViewItemClickListener.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.listener.itemclick;\n\nimport android.view.MotionEvent;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.evrencoskun.tableview.ITableView;\nimport com.evrencoskun.tableview.adapter.recyclerview.CellRecyclerView;\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder;\n\n/**\n * Created by evrencoskun on 26/09/2017.\n */\n\npublic class RowHeaderRecyclerViewItemClickListener extends AbstractItemClickListener {\n\n    public RowHeaderRecyclerViewItemClickListener(@NonNull CellRecyclerView recyclerView, @NonNull ITableView\n            tableView) {\n        super(recyclerView, tableView);\n    }\n\n    @Override\n    protected boolean clickAction(@NonNull RecyclerView view, @NonNull MotionEvent e) {\n        // Get interacted view from x,y coordinate.\n        View childView = view.findChildViewUnder(e.getX(), e.getY());\n\n        if (childView != null) {\n            // Find the view holder\n            AbstractViewHolder holder = (AbstractViewHolder) mRecyclerView.getChildViewHolder\n                    (childView);\n\n            int row = holder.getBindingAdapterPosition();\n\n            // Control to ignore selection color\n            if (!mTableView.isIgnoreSelectionColors()) {\n                mSelectionHandler.setSelectedRowPosition(holder, row);\n            }\n\n            // Call ITableView listener for item click\n            getTableViewListener().onRowHeaderClicked(holder, row);\n            return true;\n        }\n        return false;\n    }\n\n    protected void longPressAction(@NonNull MotionEvent e) {\n        // Consume the action for the time when the recyclerView is scrolling.\n        if (mRecyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {\n            return;\n        }\n\n        // Get interacted view from x,y coordinate.\n        View child = mRecyclerView.findChildViewUnder(e.getX(), e.getY());\n\n        if (child != null) {\n            // Find the view holder\n            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(child);\n\n            // Call ITableView listener for long click\n            getTableViewListener().onRowHeaderLongPressed(holder, holder.getBindingAdapterPosition());\n        }\n    }\n\n    @Override\n    protected boolean doubleClickAction(@NonNull MotionEvent e) {\n        // Get interacted view from x,y coordinate.\n        View childView = mRecyclerView.findChildViewUnder(e.getX(), e.getY());\n\n        if (childView != null) {\n            // Find the view holder\n            AbstractViewHolder holder = (AbstractViewHolder) mRecyclerView.getChildViewHolder\n                    (childView);\n\n            int row = holder.getBindingAdapterPosition();\n\n            // Control to ignore selection color\n            if (!mTableView.isIgnoreSelectionColors()) {\n                mSelectionHandler.setSelectedRowPosition(holder, row);\n            }\n\n            // Call ITableView listener for item click\n            getTableViewListener().onRowHeaderDoubleClicked(holder, row);\n            return true;\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/listener/scroll/HorizontalRecyclerViewListener.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.listener.scroll;\n\nimport android.util.Log;\nimport android.view.MotionEvent;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.evrencoskun.tableview.ITableView;\nimport com.evrencoskun.tableview.adapter.recyclerview.CellRecyclerView;\n\n/**\n * Created by evrencoskun on 19/06/2017.\n */\n\npublic class HorizontalRecyclerViewListener extends RecyclerView.OnScrollListener implements\n        RecyclerView.OnItemTouchListener {\n\n    private static final String LOG_TAG = HorizontalRecyclerViewListener.class.getSimpleName();\n\n    @NonNull\n    private final CellRecyclerView mColumnHeaderRecyclerView;\n    @Nullable\n    private final RecyclerView.LayoutManager mCellLayoutManager;\n    @Nullable\n    private RecyclerView mLastTouchedRecyclerView;\n\n    // X position means column position\n    private int mXPosition;\n    private boolean mIsMoved;\n\n    private int mScrollPosition;\n    private int mScrollPositionOffset = 0;\n\n    @Nullable\n    private RecyclerView mCurrentRVTouched = null;\n\n    @NonNull\n    private final VerticalRecyclerViewListener mVerticalRecyclerViewListener;\n\n    public HorizontalRecyclerViewListener(@NonNull ITableView tableView) {\n        this.mColumnHeaderRecyclerView = tableView.getColumnHeaderRecyclerView();\n        this.mCellLayoutManager = tableView.getCellRecyclerView().getLayoutManager();\n        this.mVerticalRecyclerViewListener = tableView.getVerticalRecyclerViewListener();\n    }\n\n    @Override\n    public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {\n\n        // Prevent multitouch, once we start to listen with a RV,\n        // we ignore any other RV until the touch is released (UP)\n        if (mCurrentRVTouched != null && rv != mCurrentRVTouched) {\n            return true;\n        }\n\n        if (e.getAction() == MotionEvent.ACTION_DOWN) {\n            mCurrentRVTouched = rv;\n            if (rv.getScrollState() == RecyclerView.SCROLL_STATE_IDLE) {\n\n                if (mLastTouchedRecyclerView != null && rv != mLastTouchedRecyclerView) {\n                    if (mLastTouchedRecyclerView == mColumnHeaderRecyclerView) {\n                        mColumnHeaderRecyclerView.removeOnScrollListener(this);\n                        mColumnHeaderRecyclerView.stopScroll();\n                        Log.d(LOG_TAG, \"Scroll listener  has been removed to \" +\n                                \"mColumnHeaderRecyclerView at last touch control\");\n                    } else {\n                        int lastTouchedIndex = getIndex(mLastTouchedRecyclerView);\n\n                        // Control whether the last touched recyclerView is still attached or not\n                        if (lastTouchedIndex >= 0 && lastTouchedIndex < mCellLayoutManager\n                                .getChildCount()) {\n                            // Control the scroll listener is already removed. For instance; if user\n                            // scroll the parent recyclerView vertically, at that time,\n                            // ACTION_CANCEL\n                            // will be triggered that removes the scroll listener of the last\n                            // touched\n                            // recyclerView.\n                            if (!((CellRecyclerView) mLastTouchedRecyclerView)\n                                    .isHorizontalScrollListenerRemoved()) {\n                                // Remove scroll listener of the last touched recyclerView\n                                // Because user touched another recyclerView before the last one get\n                                // SCROLL_STATE_IDLE state that removes the scroll listener\n                                ((RecyclerView) mCellLayoutManager.getChildAt(lastTouchedIndex))\n                                        .removeOnScrollListener(this);\n\n                                Log.d(LOG_TAG, \"Scroll listener  has been removed to \" +\n                                        mLastTouchedRecyclerView.getId() + \" CellRecyclerView \" +\n                                        \"at last touch control\");\n\n                                // the last one scroll must be stopped to be sync with others\n                                ((RecyclerView) mCellLayoutManager.getChildAt(lastTouchedIndex))\n                                        .stopScroll();\n                            }\n                        }\n                    }\n                }\n\n                mXPosition = ((CellRecyclerView) rv).getScrolledX();\n                rv.addOnScrollListener(this);\n                Log.d(LOG_TAG, \"Scroll listener  has been added to \" + rv.getId() + \" at action \"\n                        + \"down\");\n            }\n        } else if (e.getAction() == MotionEvent.ACTION_MOVE) {\n            mCurrentRVTouched = rv;\n            // Why does it matter ?\n            // user scroll any recyclerView like brushing, at that time, ACTION_UP will be\n            // triggered\n            // before scrolling. So, we need to store whether it moved or not.\n            mIsMoved = true;\n        } else if (e.getAction() == MotionEvent.ACTION_UP) {\n            mCurrentRVTouched = null;\n            int nScrollX = ((CellRecyclerView) rv).getScrolledX();\n            // Is it just touched without scrolling then remove the listener\n            if (mXPosition == nScrollX && !mIsMoved) {\n                rv.removeOnScrollListener(this);\n                Log.d(LOG_TAG, \"Scroll listener  has been removed to \" + rv.getId() + \" at \" +\n                        \"action\" + \" up\");\n            }\n\n            mLastTouchedRecyclerView = rv;\n\n        } else if (e.getAction() == MotionEvent.ACTION_CANCEL) {\n            // ACTION_CANCEL action will be triggered if users try to scroll vertically\n            // For this situation, it doesn't matter whether the x position is changed or not\n            // Beside this, even if moved action will be triggered, scroll listener won't\n            // triggered on cancel action. So, we need to change state of the mIsMoved value as\n            // well.\n\n            // Renew the scroll position and its offset\n            renewScrollPosition(rv);\n\n            rv.removeOnScrollListener(this);\n            Log.d(LOG_TAG, \"Scroll listener  has been removed to \" + rv.getId() + \" at action \" +\n                    \"cancel\");\n\n            mIsMoved = false;\n\n            mLastTouchedRecyclerView = rv;\n\n            mCurrentRVTouched = null;\n        }\n\n        return false;\n    }\n\n    @Override\n    public void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {\n    }\n\n    @Override\n    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {\n    }\n\n    @Override\n    public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {\n        // Column Header should be scrolled firstly. Because it is the compared recyclerView to\n        // make column width fit.\n\n        if (recyclerView == mColumnHeaderRecyclerView) {\n            super.onScrolled(recyclerView, dx, dy);\n\n            // Scroll each cell recyclerViews\n            for (int i = 0; i < mCellLayoutManager.getChildCount(); i++) {\n                CellRecyclerView child = (CellRecyclerView) mCellLayoutManager.getChildAt(i);\n                // Scroll horizontally\n                child.scrollBy(dx, 0);\n            }\n        } else {\n            // Scroll column header recycler view as well\n            //mColumnHeaderRecyclerView.scrollBy(dx, 0);\n\n            super.onScrolled(recyclerView, dx, dy);\n\n            // Scroll each cell recyclerViews except the current touched one\n            for (int i = 0; i < mCellLayoutManager.getChildCount(); i++) {\n                CellRecyclerView child = (CellRecyclerView) mCellLayoutManager.getChildAt(i);\n                if (child != recyclerView) {\n                    // Scroll horizontally\n                    child.scrollBy(dx, 0);\n                }\n            }\n        }\n    }\n\n    @Override\n    public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {\n        super.onScrollStateChanged(recyclerView, newState);\n\n        if (newState == RecyclerView.SCROLL_STATE_IDLE) {\n            // Renew the scroll position and its offset\n            renewScrollPosition(recyclerView);\n\n            recyclerView.removeOnScrollListener(this);\n            Log.d(LOG_TAG, \"Scroll listener has been removed to \" + recyclerView.getId() + \" at \"\n                    + \"onScrollStateChanged\");\n            mIsMoved = false;\n\n            // When a user scrolls horizontally, VerticalRecyclerView add vertical scroll\n            // listener because of touching process.However, mVerticalRecyclerViewListener\n            // doesn't know anything about it. So, it is necessary to remove the last touched\n            // recyclerView which uses the mVerticalRecyclerViewListener.\n            boolean isNeeded = mLastTouchedRecyclerView != mColumnHeaderRecyclerView;\n            mVerticalRecyclerViewListener.removeLastTouchedRecyclerViewScrollListener(isNeeded);\n        }\n    }\n\n    private int getIndex(@NonNull RecyclerView rv) {\n        for (int i = 0; i < mCellLayoutManager.getChildCount(); i++) {\n            if (mCellLayoutManager.getChildAt(i) == rv) {\n                return i;\n            }\n        }\n        return -1;\n    }\n\n    /**\n     * This method calculates the current scroll position and its offset to help new attached\n     * recyclerView on window at that position and offset\n     *\n     * @see #getScrollPosition()\n     * @see #getScrollPositionOffset()\n     */\n    private void renewScrollPosition(@NonNull RecyclerView recyclerView) {\n        LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();\n        mScrollPosition = layoutManager.findFirstCompletelyVisibleItemPosition();\n\n        // That means there is no completely visible Position.\n        if (mScrollPosition == -1) {\n            mScrollPosition = layoutManager.findFirstVisibleItemPosition();\n\n            // That means there is just a visible item on the screen\n            if (mScrollPosition == layoutManager.findLastVisibleItemPosition()) {\n                // in this case we use the position which is the last & first visible item.\n            } else {\n                // That means there are 2 visible item on the screen. However, second one is not\n                // completely visible.\n                mScrollPosition = mScrollPosition + 1;\n            }\n        }\n\n        mScrollPositionOffset = layoutManager.findViewByPosition(mScrollPosition).getLeft();\n    }\n\n    /**\n     * When parent RecyclerView scrolls vertically, the child horizontal recycler views should be\n     * displayed on right scroll position. So the first complete visible position of the\n     * recyclerView is stored as a member to use it for a new attached recyclerview whose\n     * orientation is horizontal as well.\n     *\n     * @see #getScrollPositionOffset()\n     */\n    public int getScrollPosition() {\n        return mScrollPosition;\n    }\n\n    /**\n     * Users can scroll the recyclerViews to the any x position which may not the exact position. So\n     * we need to know store the offset value to locate a specific location for a new attached\n     * recyclerView\n     *\n     * @see #getScrollPosition()\n     */\n    public int getScrollPositionOffset() {\n        return mScrollPositionOffset;\n    }\n\n    public void setScrollPositionOffset(int offset) {\n        mScrollPositionOffset = offset;\n    }\n\n    /**\n     * To change default scroll position that is before TableView is not populated.\n     */\n    public void setScrollPosition(int position) {\n        this.mScrollPosition = position;\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/listener/scroll/VerticalRecyclerViewListener.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.listener.scroll;\n\nimport android.util.Log;\nimport android.view.MotionEvent;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.evrencoskun.tableview.ITableView;\nimport com.evrencoskun.tableview.adapter.recyclerview.CellRecyclerView;\n\n/**\n * Created by evrencoskun on 30/06/2017.\n */\n\npublic class VerticalRecyclerViewListener extends RecyclerView.OnScrollListener implements\n        RecyclerView.OnItemTouchListener {\n\n    private static final String LOG_TAG = VerticalRecyclerViewListener.class.getSimpleName();\n\n    @NonNull\n    private final CellRecyclerView mRowHeaderRecyclerView, mCellRecyclerView;\n    private RecyclerView mLastTouchedRecyclerView;\n\n    // Y Position means row position\n    private int mYPosition;\n    private boolean mIsMoved;\n\n    @Nullable\n    private RecyclerView mCurrentRVTouched = null;\n\n    public VerticalRecyclerViewListener(@NonNull ITableView tableView) {\n        this.mRowHeaderRecyclerView = tableView.getRowHeaderRecyclerView();\n        this.mCellRecyclerView = tableView.getCellRecyclerView();\n    }\n\n    private float dx = 0, dy = 0;\n\n    /**\n     * check which direction the user is scrolling\n     *\n     * @param ev\n     * @return\n     */\n    private boolean verticalDirection(@NonNull MotionEvent ev) {\n        if (ev.getAction() == MotionEvent.ACTION_MOVE) {\n            if (dx == 0) {\n                dx = ev.getX();\n            }\n            if (dy == 0) {\n                dy = ev.getY();\n            }\n            float xdiff = Math.abs(dx - ev.getX());\n            float ydiff = Math.abs(dy - ev.getY());\n            dx = ev.getX();\n            dy = ev.getY();\n\n            // if user scrolled more horizontally than vertically\n            return xdiff <= ydiff;\n        }\n\n        return true;\n    }\n\n    @Override\n    public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {\n\n        // Prevent multitouch, once we start to listen with a RV,\n        // we ignore any other RV until the touch is released (UP)\n        if ((mCurrentRVTouched != null && rv != mCurrentRVTouched)) {\n            return true;\n        }\n\n        // If scroll direction is not Vertical, then ignore and reset last RV touched\n        if (!verticalDirection(e)) {\n            mCurrentRVTouched = null;\n            return false;\n        }\n\n        if (e.getAction() == MotionEvent.ACTION_DOWN) {\n            mCurrentRVTouched = rv;\n            if (rv.getScrollState() == RecyclerView.SCROLL_STATE_IDLE) {\n\n                if (mLastTouchedRecyclerView != null && rv != mLastTouchedRecyclerView) {\n                    removeLastTouchedRecyclerViewScrollListener(false);\n                }\n                mYPosition = ((CellRecyclerView) rv).getScrolledY();\n                rv.addOnScrollListener(this);\n\n                if (rv == mCellRecyclerView) {\n                    Log.d(LOG_TAG, \"mCellRecyclerView scroll listener added\");\n                } else if (rv == mRowHeaderRecyclerView) {\n                    Log.d(LOG_TAG, \"mRowHeaderRecyclerView scroll listener added\");\n                }\n\n                // Refresh the value;\n                mIsMoved = false;\n            }\n        } else if (e.getAction() == MotionEvent.ACTION_MOVE) {\n            mCurrentRVTouched = rv;\n            // Why does it matter ?\n            // user scroll any recyclerView like brushing, at that time, ACTION_UP will be\n            // triggered\n            // before scrolling. So, we need to store whether it moved or not.\n            mIsMoved = true;\n        } else if (e.getAction() == MotionEvent.ACTION_UP) {\n            mCurrentRVTouched = null;\n            int nScrollY = ((CellRecyclerView) rv).getScrolledY();\n\n            // TODO: Even if moved value is true and it may not scroll. This should be fixed.\n            // TODO: The scenario is scroll lightly center RecyclerView vertically.\n            // TODO: Below if condition may be changed later.\n\n            // Is it just touched without scrolling then remove the listener\n            if (mYPosition == nScrollY && !mIsMoved && rv.getScrollState() == RecyclerView\n                    .SCROLL_STATE_IDLE) {\n                rv.removeOnScrollListener(this);\n\n                if (rv == mCellRecyclerView) {\n                    Log.d(LOG_TAG, \"mCellRecyclerView scroll listener removed from up \");\n                } else if (rv == mRowHeaderRecyclerView) {\n                    Log.d(LOG_TAG, \"mRowHeaderRecyclerView scroll listener removed from up\");\n                }\n            }\n\n            mLastTouchedRecyclerView = rv;\n\n        }\n\n        return false;\n    }\n\n    @Override\n    public void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {\n    }\n\n    @Override\n    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {\n    }\n\n    @Override\n    public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {\n        // CellRecyclerViews should be scrolled after the RowHeaderRecyclerView.\n        // Because it is one of the main compared criterion to make each columns fit.\n\n        if (recyclerView == mCellRecyclerView) {\n            super.onScrolled(recyclerView, dx, dy);\n            // The below code has been moved in CellLayoutManager\n            //mRowHeaderRecyclerView.scrollBy(0, dy);\n\n        } else if (recyclerView == mRowHeaderRecyclerView) {\n            super.onScrolled(recyclerView, dx, dy);\n\n            mCellRecyclerView.scrollBy(0, dy);\n        }\n    }\n\n    @Override\n    public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {\n        super.onScrollStateChanged(recyclerView, newState);\n\n        if (newState == RecyclerView.SCROLL_STATE_IDLE) {\n            recyclerView.removeOnScrollListener(this);\n            mIsMoved = false;\n            mCurrentRVTouched = null;\n            if (recyclerView == mCellRecyclerView) {\n                Log.d(LOG_TAG, \"mCellRecyclerView scroll listener removed from \" +\n                        \"onScrollStateChanged\");\n            } else if (recyclerView == mRowHeaderRecyclerView) {\n                Log.d(LOG_TAG, \"mRowHeaderRecyclerView scroll listener removed from \" +\n                        \"onScrollStateChanged\");\n            }\n        }\n    }\n\n    /**\n     * If current recyclerView that is touched to scroll is not same as the last one, this method\n     * helps to remove the scroll listener of the last touched recyclerView.\n     * This method is a little bit different from HorizontalRecyclerViewListener.\n     *\n     * @param isNeeded Is mCellRecyclerView scroll listener should be removed ? The scenario is a\n     *                 user scrolls vertically using RowHeaderRecyclerView. After that, the user\n     *                 scrolls horizontally using ColumnHeaderRecyclerView.\n     */\n    public void removeLastTouchedRecyclerViewScrollListener(boolean isNeeded) {\n\n        if (mLastTouchedRecyclerView == mCellRecyclerView) {\n            mCellRecyclerView.removeOnScrollListener(this);\n            mCellRecyclerView.stopScroll();\n            Log.d(LOG_TAG, \"mCellRecyclerView scroll listener removed from last touched\");\n        } else {\n            mRowHeaderRecyclerView.removeOnScrollListener(this);\n            mRowHeaderRecyclerView.stopScroll();\n            Log.d(LOG_TAG, \"mRowHeaderRecyclerView scroll listener removed from last touched\");\n            if (isNeeded) {\n                mCellRecyclerView.removeOnScrollListener(this);\n                mCellRecyclerView.stopScroll();\n                Log.d(LOG_TAG, \"mCellRecyclerView scroll listener removed from last touched\");\n            }\n\n        }\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/pagination/IPagination.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.pagination;\n\nimport androidx.annotation.Nullable;\n\npublic interface IPagination {\n\n    /**\n     * Loads the next page of the data set to the table view.\n     */\n    void nextPage();\n\n    /**\n     * Loads the previous page of the data set to the table view.\n     */\n    void previousPage();\n\n    /**\n     * Loads the data set of the specified page to the table view.\n     *\n     * @param page The page to be loaded.\n     */\n    void goToPage(int page);\n\n    /**\n     * Sets the number of items (rows) per page to be displayed in the table view.\n     *\n     * @param numItems The number of items per page.\n     */\n    void setItemsPerPage(int numItems);\n\n    /**\n     * Sets the OnTableViewPageTurnedListener for this Pagination.\n     *\n     * @param onTableViewPageTurnedListener The OnTableViewPageTurnedListener.\n     */\n    void setOnTableViewPageTurnedListener(@Nullable Pagination.OnTableViewPageTurnedListener onTableViewPageTurnedListener);\n\n    /**\n     * Removes the OnTableViewPageTurnedListener for this Pagination.\n     */\n    void removeOnTableViewPageTurnedListener();\n\n    /**\n     * @return The current page loaded to the table view.\n     */\n    int getCurrentPage();\n\n    /**\n     * @return The number of items per page loaded to the table view.\n     */\n    int getItemsPerPage();\n\n    /**\n     * @return The number of pages in the pagination.\n     */\n    int getPageCount();\n\n    /**\n     * @return Current pagination state of the table view.\n     */\n    boolean isPaginated();\n\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/pagination/Pagination.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.pagination;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.evrencoskun.tableview.ITableView;\nimport com.evrencoskun.tableview.adapter.AdapterDataSetChangedListener;\nimport com.evrencoskun.tableview.adapter.recyclerview.CellRecyclerViewAdapter;\nimport com.evrencoskun.tableview.adapter.recyclerview.RowHeaderRecyclerViewAdapter;\nimport com.evrencoskun.tableview.filter.FilterChangedListener;\nimport com.evrencoskun.tableview.sort.ColumnForRowHeaderSortComparator;\nimport com.evrencoskun.tableview.sort.ColumnSortComparator;\nimport com.evrencoskun.tableview.sort.ColumnSortStateChangedListener;\nimport com.evrencoskun.tableview.sort.ISortableModel;\nimport com.evrencoskun.tableview.sort.RowHeaderForCellSortComparator;\nimport com.evrencoskun.tableview.sort.RowHeaderSortComparator;\nimport com.evrencoskun.tableview.sort.SortState;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\npublic class Pagination implements IPagination {\n\n    private static final int DEFAULT_ITEMS_PER_PAGE = 10;\n    private int itemsPerPage;\n    private int currentPage;\n    private int pageCount;\n    @NonNull\n    private List<List<ISortableModel>> originalCellData;\n    @NonNull\n    private List<ISortableModel> originalRowData;\n    @Nullable\n    private RowHeaderRecyclerViewAdapter<ISortableModel> mRowHeaderRecyclerViewAdapter;\n    @Nullable\n    private CellRecyclerViewAdapter<List<ISortableModel>> mCellRecyclerViewAdapter;\n    @Nullable\n    private OnTableViewPageTurnedListener onTableViewPageTurnedListener;\n\n    /**\n     * Basic constructor, TableView instance is required.\n     *\n     * @param tableView The TableView to be paginated.\n     */\n    public Pagination(@NonNull ITableView tableView) {\n        this(tableView, DEFAULT_ITEMS_PER_PAGE, null);\n    }\n\n    /**\n     * Applies pagination to the supplied TableView with number of items per page.\n     *\n     * @param tableView    The TableView to be paginated.\n     * @param itemsPerPage The number of items per page.\n     */\n    public Pagination(@NonNull ITableView tableView, int itemsPerPage) {\n        this(tableView, itemsPerPage, null);\n    }\n\n    /**\n     * Applies pagination to the supplied TableView with number of items per page and an\n     * OnTableViewPageTurnedListener for handling changes in the TableView pagination.\n     *\n     * @param tableView    The TableView to be paginated.\n     * @param itemsPerPage The number of items per page.\n     * @param listener     The OnTableViewPageTurnedListener for the TableView.\n     */\n    public Pagination(@NonNull ITableView tableView, int itemsPerPage, @Nullable OnTableViewPageTurnedListener listener) {\n        initialize(tableView, itemsPerPage, listener);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private void initialize(@NonNull ITableView tableView, int itemsPerPage, @Nullable OnTableViewPageTurnedListener listener) {\n        this.onTableViewPageTurnedListener = listener;\n        this.itemsPerPage = itemsPerPage;\n        this.mRowHeaderRecyclerViewAdapter = (RowHeaderRecyclerViewAdapter) tableView\n                .getRowHeaderRecyclerView().getAdapter();\n        this.mCellRecyclerViewAdapter = (CellRecyclerViewAdapter) tableView.getCellRecyclerView()\n                .getAdapter();\n        tableView.getColumnSortHandler().addColumnSortStateChangedListener(columnSortStateChangedListener);\n        tableView.getAdapter().addAdapterDataSetChangedListener(adapterDataSetChangedListener);\n        tableView.getFilterHandler().addFilterChangedListener(filterChangedListener);\n        this.originalCellData = tableView.getAdapter().getCellRecyclerViewAdapter().getItems();\n        this.originalRowData = tableView.getAdapter().getRowHeaderRecyclerViewAdapter().getItems();\n        this.currentPage = 1;\n        reloadPages();\n    }\n\n    private void reloadPages() {\n        paginateData();\n        goToPage(currentPage);\n    }\n\n    private void paginateData() {\n        int start, end;\n        List<List<ISortableModel>> currentPageCellData = new ArrayList<>();\n        List<ISortableModel> currentPageRowData = new ArrayList<>();\n        // No pagination if itemsPerPage is 0, all data will be loaded into the TableView.\n        if (itemsPerPage == 0) {\n            currentPageCellData.addAll(originalCellData);\n            currentPageRowData.addAll(originalRowData);\n            pageCount = 1;\n            start = 0;\n            end = currentPageCellData.size();\n        } else {\n            start = (currentPage * itemsPerPage) - itemsPerPage;\n            end = (currentPage * itemsPerPage) > originalCellData.size() ?\n                    originalCellData.size() : (currentPage * itemsPerPage);\n\n            for (int x = start; x < end; x++) {\n                currentPageCellData.add(originalCellData.get(x));\n                currentPageRowData.add(originalRowData.get(x));\n            }\n\n            // Using ceiling to calculate number of pages, e.g. 103 items of 10 items per page\n            // will result to 11 pages.\n            pageCount = (int) Math.ceil((double) originalCellData.size() / itemsPerPage);\n        }\n\n        // Sets the paginated data to the TableView.\n        mRowHeaderRecyclerViewAdapter.setItems(currentPageRowData, true);\n        mCellRecyclerViewAdapter.setItems(currentPageCellData, true);\n\n        // Dispatches TableView changes to Listener interface\n        if (onTableViewPageTurnedListener != null) {\n            onTableViewPageTurnedListener.onPageTurned(currentPageCellData.size(), start, end - 1);\n        }\n    }\n\n    @Override\n    public void nextPage() {\n        currentPage = currentPage + 1 > pageCount ? currentPage : ++currentPage;\n        paginateData();\n    }\n\n    @Override\n    public void previousPage() {\n        currentPage = currentPage - 1 == 0 ? currentPage : --currentPage;\n        paginateData();\n    }\n\n    @Override\n    public void goToPage(int page) {\n        currentPage = (page > pageCount || page < 1) ? (page > pageCount && pageCount > 0 ? pageCount : currentPage) : page;\n        paginateData();\n    }\n\n    @Override\n    public void setItemsPerPage(int numItems) {\n        itemsPerPage = numItems;\n        currentPage = 1;\n        paginateData();\n    }\n\n    @Override\n    public void setOnTableViewPageTurnedListener(@Nullable OnTableViewPageTurnedListener onTableViewPageTurnedListener) {\n        this.onTableViewPageTurnedListener = onTableViewPageTurnedListener;\n    }\n\n    @Override\n    public void removeOnTableViewPageTurnedListener() {\n        this.onTableViewPageTurnedListener = null;\n    }\n\n    @Override\n    public int getCurrentPage() {\n        return currentPage;\n    }\n\n    @Override\n    public int getItemsPerPage() {\n        return itemsPerPage;\n    }\n\n    @Override\n    public int getPageCount() {\n        return pageCount;\n    }\n\n    @Override\n    public boolean isPaginated() {\n        return itemsPerPage > 0;\n    }\n\n    @NonNull\n    @SuppressWarnings(\"unchecked\")\n    private final AdapterDataSetChangedListener adapterDataSetChangedListener =\n            new AdapterDataSetChangedListener() {\n                @Override\n                public void onRowHeaderItemsChanged(@NonNull List rowHeaderItems) {\n                    originalRowData = new ArrayList<>(rowHeaderItems);\n                    reloadPages();\n                }\n\n                @Override\n                public void onCellItemsChanged(@NonNull List cellItems) {\n                    originalCellData = new ArrayList<>(cellItems);\n                    reloadPages();\n                }\n            };\n\n    @NonNull\n    private final FilterChangedListener<ISortableModel> filterChangedListener =\n            new FilterChangedListener<ISortableModel>() {\n                @Override\n                public void onFilterChanged(@NonNull List<List<ISortableModel>> filteredCellItems, @NonNull List<ISortableModel> filteredRowHeaderItems) {\n                    originalCellData = new ArrayList<>(filteredCellItems);\n                    originalRowData = new ArrayList<>(filteredRowHeaderItems);\n                    reloadPages();\n                }\n\n                @Override\n                public void onFilterCleared(@NonNull List<List<ISortableModel>> originalCellItems, @NonNull List<ISortableModel> originalRowHeaderItems) {\n                    originalCellData = new ArrayList<>(originalCellItems);\n                    originalRowData = new ArrayList<>(originalRowHeaderItems);\n                    reloadPages();\n                }\n            };\n\n    @NonNull\n    private final ColumnSortStateChangedListener columnSortStateChangedListener =\n            new ColumnSortStateChangedListener() {\n                @Override\n                public void onColumnSortStatusChanged(int column, @NonNull SortState sortState) {\n                    paginateOnColumnSort(column, sortState);\n                }\n\n                @Override\n                public void onRowHeaderSortStatusChanged(@NonNull SortState sortState) {\n                    paginateOnColumnSort(-1, sortState);\n                }\n            };\n\n    private void paginateOnColumnSort(int column, @NonNull SortState sortState) {\n        List<ISortableModel> sortedRowHeaderList = new ArrayList<>(originalRowData);\n        List<List<ISortableModel>> sortedList = new ArrayList<>(originalCellData);\n        if (sortState != SortState.UNSORTED) {\n            if (column == -1) {\n                Collections.sort(sortedRowHeaderList, new RowHeaderSortComparator(sortState));\n                RowHeaderForCellSortComparator rowHeaderForCellSortComparator =\n                        new RowHeaderForCellSortComparator(\n                                originalRowData,\n                                originalCellData,\n                                sortState\n                        );\n\n                Collections.sort(sortedList, rowHeaderForCellSortComparator);\n            } else {\n                Collections.sort(sortedList, new ColumnSortComparator(column, sortState));\n                ColumnForRowHeaderSortComparator columnForRowHeaderSortComparator =\n                        new ColumnForRowHeaderSortComparator(\n                                originalRowData,\n                                originalCellData,\n                                column,\n                                sortState\n                        );\n\n                Collections.sort(sortedRowHeaderList, columnForRowHeaderSortComparator);\n            }\n        }\n\n        originalRowData = new ArrayList<>(sortedRowHeaderList);\n        originalCellData = new ArrayList<>(sortedList);\n        reloadPages();\n    }\n\n    /**\n     * Listener interface for changing of TableView page.\n     */\n    public interface OnTableViewPageTurnedListener {\n\n        /**\n         * Called when the page is changed in the TableView.\n         *\n         * @param numItems   The number of items currently being displayed in the TableView.\n         * @param itemsStart The starting item currently being displayed in the TableView.\n         * @param itemsEnd   The ending item currently being displayed in the TableView.\n         */\n        void onPageTurned(int numItems, int itemsStart, int itemsEnd);\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/preference/Preferences.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.preference;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\n\n/**\n * Created by evrencoskun on 4.03.2018.\n */\n\npublic class Preferences implements Parcelable {\n\n    public int rowPosition;\n    public int rowPositionOffset;\n    public int columnPosition;\n    public int columnPositionOffset;\n    public int selectedRowPosition;\n    public int selectedColumnPosition;\n\n    public Preferences() {\n    }\n\n    protected Preferences(Parcel in) {\n        rowPosition = in.readInt();\n        rowPositionOffset = in.readInt();\n        columnPosition = in.readInt();\n        columnPositionOffset = in.readInt();\n        selectedRowPosition = in.readInt();\n        selectedColumnPosition = in.readInt();\n    }\n\n    @NonNull\n    public static final Creator<Preferences> CREATOR = new Creator<Preferences>() {\n        @NonNull\n        @Override\n        public Preferences createFromParcel(Parcel in) {\n            return new Preferences(in);\n        }\n\n        @NonNull\n        @Override\n        public Preferences[] newArray(int size) {\n            return new Preferences[size];\n        }\n    };\n\n\n    /**\n     * Describe the kinds of special objects contained in this Parcelable\n     * instance's marshaled representation. For example, if the object will\n     * include a file descriptor in the output of {@link #writeToParcel(Parcel, int)},\n     * the return value of this method must include the\n     * {@link #CONTENTS_FILE_DESCRIPTOR} bit.\n     *\n     * @return a bitmask indicating the set of special object types marshaled by this Parcelable\n     * object instance.\n     */\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    /**\n     * Flatten this object in to a Parcel.\n     *\n     * @param dest  The Parcel in which the object should be written.\n     * @param flags Additional flags about how the object should be written. May be 0 or {@link\n     *              #PARCELABLE_WRITE_RETURN_VALUE}.\n     */\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeInt(rowPosition);\n        dest.writeInt(rowPositionOffset);\n        dest.writeInt(columnPosition);\n        dest.writeInt(columnPositionOffset);\n        dest.writeInt(selectedRowPosition);\n        dest.writeInt(selectedColumnPosition);\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/preference/SavedState.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.preference;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\n\n/**\n * Created by evrencoskun on 4.03.2018.\n */\n\npublic class SavedState extends View.BaseSavedState {\n\n    public Preferences preferences;\n\n    public SavedState(Parcelable superState) {\n        super(superState);\n    }\n\n    private SavedState(Parcel in) {\n        super(in);\n        preferences = in.readParcelable(Preferences.class.getClassLoader());\n    }\n\n    @Override\n    public void writeToParcel(Parcel out, int flags) {\n        super.writeToParcel(out, flags);\n        out.writeParcelable(preferences, flags);\n    }\n\n    @NonNull\n    public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable\n            .Creator<SavedState>() {\n        @NonNull\n        public SavedState createFromParcel(Parcel in) {\n            return new SavedState(in);\n        }\n\n        @NonNull\n        public SavedState[] newArray(int size) {\n            return new SavedState[size];\n        }\n    };\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/sort/AbstractSortComparator.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.sort;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.util.Date;\n\n/**\n * Created by cedricferry on 6/2/18.\n */\n\npublic abstract class AbstractSortComparator {\n    @NonNull\n    protected SortState mSortState;\n\n    protected int compareContent(@Nullable Object o1, @Nullable Object o2) {\n        if (o1 == null && o2 == null) {\n            return 0;\n        } else if (o1 == null) {\n            return -1;\n        } else if (o2 == null) {\n            return 1;\n        } else {\n            Class type = o1.getClass();\n            if (Comparable.class.isAssignableFrom(type)) {\n                return ((Comparable) o1).compareTo(o2);\n            } else if (type.getSuperclass() == Number.class) {\n                return compare((Number) o1, (Number) o2);\n            } else if (type == String.class) {\n                return ((String) o1).compareTo((String) o2);\n            } else if (type == Date.class) {\n                return compare((Date) o1, (Date) o2);\n            } else if (type == Boolean.class) {\n                return compare((Boolean) o1, (Boolean) o2);\n            } else {\n                return ((String) o1).compareTo((String) o2);\n            }\n        }\n    }\n\n    public int compare(Number o1, Number o2) {\n        double n1 = o1.doubleValue();\n        double n2 = o2.doubleValue();\n\n        return Double.compare(n1, n2);\n    }\n\n    public int compare(Date o1, Date o2) {\n        long n1 = o1.getTime();\n        long n2 = o2.getTime();\n\n        return Long.compare(n1, n2);\n    }\n\n    public int compare(Boolean o1, Boolean o2) {\n        return Boolean.compare(o1, o2);\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/sort/ColumnForRowHeaderSortComparator.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.sort;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.Comparator;\nimport java.util.List;\n\n/**\n * In order to keep RowHeader DataSet and Main DataSet aligned\n * it is required to sort RowHeader the same.\n * So if MainDataSet row 1 moved to position 10, RowHeader 1 move to position 10 too.\n * To accomplish that we need to set a comparator that use MainDataSet\n * in order to sort RowHeader.\n * Created by cedricferry on 7/2/18.\n */\npublic class ColumnForRowHeaderSortComparator implements Comparator<ISortableModel> {\n    @NonNull\n    private final List<ISortableModel> mRowHeaderList;\n    @NonNull\n    private final List<List<ISortableModel>> mReferenceList;\n    private final int column;\n    @NonNull\n    private final SortState mSortState;\n    @NonNull\n    private final ColumnSortComparator mColumnSortComparator;\n\n    public ColumnForRowHeaderSortComparator(@NonNull List<ISortableModel> rowHeader,\n                                            @NonNull List<List<ISortableModel>> referenceList,\n                                            int column,\n                                            @NonNull SortState sortState) {\n        this.mRowHeaderList = rowHeader;\n        this.mReferenceList = referenceList;\n        this.column = column;\n        this.mSortState = sortState;\n        this.mColumnSortComparator = new ColumnSortComparator(column, sortState);\n    }\n\n    @Override\n    public int compare(ISortableModel o, ISortableModel t1) {\n        Object o1 = mReferenceList.get(this.mRowHeaderList.indexOf(o)).get(column).getContent();\n        Object o2 = mReferenceList.get(this.mRowHeaderList.indexOf(t1)).get(column).getContent();\n        if (mSortState == SortState.DESCENDING) {\n            return mColumnSortComparator.compareContent(o2, o1);\n        } else {\n            return mColumnSortComparator.compareContent(o1, o2);\n        }\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/sort/ColumnSortCallback.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.sort;\n\nimport androidx.annotation.NonNull;\nimport androidx.core.util.ObjectsCompat;\nimport androidx.recyclerview.widget.DiffUtil;\n\nimport java.util.List;\n\n/**\n * Created by evrencoskun on 23.11.2017.\n */\n\npublic class ColumnSortCallback extends DiffUtil.Callback {\n    @NonNull\n    private final List<List<ISortableModel>> mOldCellItems;\n    @NonNull\n    private final List<List<ISortableModel>> mNewCellItems;\n    private final int mColumnPosition;\n\n    public ColumnSortCallback(@NonNull List<List<ISortableModel>> oldCellItems, @NonNull List<List<ISortableModel>>\n            newCellItems, int column) {\n        this.mOldCellItems = oldCellItems;\n        this.mNewCellItems = newCellItems;\n        this.mColumnPosition = column;\n    }\n\n    @Override\n    public int getOldListSize() {\n        return mOldCellItems.size();\n    }\n\n    @Override\n    public int getNewListSize() {\n        return mNewCellItems.size();\n    }\n\n    @Override\n    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {\n        // Control for precaution from IndexOutOfBoundsException\n        if (mOldCellItems.size() > oldItemPosition && mNewCellItems.size() > newItemPosition) {\n            if (mOldCellItems.get(oldItemPosition).size() > mColumnPosition && mNewCellItems.get\n                    (newItemPosition).size() > mColumnPosition) {\n                // Compare ids\n                String oldId = mOldCellItems.get(oldItemPosition).get(mColumnPosition).getId();\n                String newId = mNewCellItems.get(newItemPosition).get(mColumnPosition).getId();\n                return oldId.equals(newId);\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {\n        // Control for precaution from IndexOutOfBoundsException\n        if (mOldCellItems.size() > oldItemPosition && mNewCellItems.size() > newItemPosition) {\n            if (mOldCellItems.get(oldItemPosition).size() > mColumnPosition && mNewCellItems.get\n                    (newItemPosition).size() > mColumnPosition) {\n                // Compare contents\n                Object oldContent = mOldCellItems.get(oldItemPosition).get(mColumnPosition)\n                        .getContent();\n                Object newContent = mNewCellItems.get(newItemPosition).get(mColumnPosition)\n                        .getContent();\n                return ObjectsCompat.equals(oldContent, newContent);\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/sort/ColumnSortComparator.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.sort;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.Comparator;\nimport java.util.List;\n\n/**\n * Created by evrencoskun on 25.11.2017.\n */\n\npublic class ColumnSortComparator extends AbstractSortComparator implements Comparator<List<ISortableModel>> {\n\n    private final int mXPosition;\n\n    public ColumnSortComparator(int xPosition, @NonNull SortState sortState) {\n        this.mXPosition = xPosition;\n        this.mSortState = sortState;\n    }\n\n    @Override\n    public int compare(List<ISortableModel> t1, List<ISortableModel> t2) {\n        Object o1 = t1.get(mXPosition).getContent();\n        Object o2 = t2.get(mXPosition).getContent();\n\n        if (mSortState == SortState.DESCENDING) {\n            return compareContent(o2, o1);\n        } else {\n            // Default sorting process is ASCENDING\n            return compareContent(o1, o2);\n        }\n    }\n\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/sort/ColumnSortHelper.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.sort;\n\nimport androidx.annotation.NonNull;\n\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractSorterViewHolder;\nimport com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder;\nimport com.evrencoskun.tableview.layoutmanager.ColumnHeaderLayoutManager;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Created by evrencoskun on 15.12.2017.\n */\n\npublic class ColumnSortHelper {\n    @NonNull\n    private final List<Directive> mSortingColumns = new ArrayList<>();\n    @NonNull\n    private final ColumnHeaderLayoutManager mColumnHeaderLayoutManager;\n\n    public ColumnSortHelper(@NonNull ColumnHeaderLayoutManager columnHeaderLayoutManager) {\n        this.mColumnHeaderLayoutManager = columnHeaderLayoutManager;\n    }\n\n    private void sortingStatusChanged(int column, @NonNull SortState sortState) {\n        AbstractViewHolder holder = mColumnHeaderLayoutManager.getViewHolder(column);\n\n        if (holder != null) {\n            if (holder instanceof AbstractSorterViewHolder) {\n                ((AbstractSorterViewHolder) holder).onSortingStatusChanged(sortState);\n\n            } else {\n                throw new IllegalArgumentException(\"Column Header ViewHolder must extend \" +\n                        \"AbstractSorterViewHolder\");\n            }\n        }\n    }\n\n    public void setSortingStatus(int column, @NonNull SortState status) {\n        Directive directive = getDirective(column);\n        if (directive != EMPTY_DIRECTIVE) {\n            mSortingColumns.remove(directive);\n        }\n        if (status != SortState.UNSORTED) {\n            mSortingColumns.add(new Directive(column, status));\n        }\n\n        sortingStatusChanged(column, status);\n    }\n\n    public void clearSortingStatus() {\n        mSortingColumns.clear();\n    }\n\n    public boolean isSorting() {\n        return mSortingColumns.size() != 0;\n    }\n\n    @NonNull\n    public SortState getSortingStatus(int column) {\n        return getDirective(column).direction;\n    }\n\n    @NonNull\n    private Directive getDirective(int column) {\n        for (int i = 0; i < mSortingColumns.size(); i++) {\n            Directive directive = mSortingColumns.get(i);\n            if (directive.column == column) {\n                return directive;\n            }\n        }\n        return EMPTY_DIRECTIVE;\n    }\n\n    private static class Directive {\n        private final int column;\n        @NonNull\n        private final SortState direction;\n\n        Directive(int column, @NonNull SortState direction) {\n            this.column = column;\n            this.direction = direction;\n        }\n    }\n\n    @NonNull\n    private static final Directive EMPTY_DIRECTIVE = new Directive(-1, SortState.UNSORTED);\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/sort/ColumnSortStateChangedListener.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.sort;\n\nimport androidx.annotation.NonNull;\n\npublic abstract class ColumnSortStateChangedListener {\n\n    /**\n     * Dispatches sorting changes on a column to listeners.\n     *\n     * @param column    Column to be sorted.\n     * @param sortState SortState of the column to be sorted.\n     */\n    public void onColumnSortStatusChanged(int column, @NonNull SortState sortState) {\n    }\n\n    /**\n     * Dispatches sorting changes to the row header column to listeners.\n     *\n     * @param sortState SortState of the row header column.\n     */\n    public void onRowHeaderSortStatusChanged(@NonNull SortState sortState) {\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/sort/ISortableModel.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.sort;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\n/**\n * Created by evrencoskun on 24.11.2017.\n */\n\npublic interface ISortableModel {\n    @NonNull\n    String getId();\n\n    @Nullable\n    Object getContent();\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/sort/RowHeaderForCellSortComparator.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.sort;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.Comparator;\nimport java.util.List;\n\n/**\n * Created by cedricferry on 14/2/18.\n */\n\npublic class RowHeaderForCellSortComparator implements Comparator<List<ISortableModel>> {\n    @NonNull\n    private final List<ISortableModel> mReferenceList;\n    @NonNull\n    private final List<List<ISortableModel>> mColumnList;\n    @NonNull\n    private final SortState mSortState;\n    @NonNull\n    private final RowHeaderSortComparator mRowHeaderSortComparator;\n\n    public RowHeaderForCellSortComparator(@NonNull List<ISortableModel> referenceList,\n                                          @NonNull List<List<ISortableModel>> columnList,\n                                          @NonNull SortState sortState) {\n        this.mReferenceList = referenceList;\n        this.mColumnList = columnList;\n        this.mSortState = sortState;\n        this.mRowHeaderSortComparator = new RowHeaderSortComparator(sortState);\n    }\n\n    @Override\n    public int compare(List<ISortableModel> o, List<ISortableModel> t1) {\n        Object o1 = mReferenceList.get(this.mColumnList.indexOf(o)).getContent();\n        Object o2 = mReferenceList.get(this.mColumnList.indexOf(t1)).getContent();\n        if (mSortState == SortState.DESCENDING) {\n            return mRowHeaderSortComparator.compareContent(o2, o1);\n        } else {\n            return mRowHeaderSortComparator.compareContent(o1, o2);\n        }\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/sort/RowHeaderSortCallback.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.sort;\n\nimport androidx.annotation.NonNull;\nimport androidx.recyclerview.widget.DiffUtil;\n\nimport java.util.List;\n\n/**\n * Created by cedricferry on 6/2/18.\n */\n\npublic class RowHeaderSortCallback extends DiffUtil.Callback {\n    @NonNull\n    private final List<ISortableModel> mOldCellItems;\n    @NonNull\n    private final List<ISortableModel> mNewCellItems;\n\n    public RowHeaderSortCallback(@NonNull List<ISortableModel> oldCellItems, @NonNull List<ISortableModel>\n            newCellItems) {\n        this.mOldCellItems = oldCellItems;\n        this.mNewCellItems = newCellItems;\n    }\n\n    @Override\n    public int getOldListSize() {\n        return mOldCellItems.size();\n    }\n\n    @Override\n    public int getNewListSize() {\n        return mNewCellItems.size();\n    }\n\n    @Override\n    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {\n        // Control for precaution from IndexOutOfBoundsException\n        if (mOldCellItems.size() > oldItemPosition && mNewCellItems.size() > newItemPosition) {\n            // Compare ids\n            String oldId = mOldCellItems.get(oldItemPosition).getId();\n            String newId = mNewCellItems.get(newItemPosition).getId();\n            return oldId.equals(newId);\n        }\n        return false;\n    }\n\n    @Override\n    public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {\n        // Control for precaution from IndexOutOfBoundsException\n        if (mOldCellItems.size() > oldItemPosition && mNewCellItems.size() > newItemPosition) {\n            // Compare contents\n            Object oldContent = mOldCellItems.get(oldItemPosition)\n                    .getContent();\n            Object newContent = mNewCellItems.get(newItemPosition)\n                    .getContent();\n            return oldContent.equals(newContent);\n        }\n\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/sort/RowHeaderSortComparator.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.sort;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.Comparator;\n\n/**\n * Created by cedricferry on 6/2/18.\n */\n\npublic class RowHeaderSortComparator extends AbstractSortComparator implements Comparator<ISortableModel> {\n\n    public RowHeaderSortComparator(@NonNull SortState sortState) {\n        this.mSortState = sortState;\n    }\n\n    @Override\n    public int compare(ISortableModel o1, ISortableModel o2) {\n        if (mSortState == SortState.DESCENDING) {\n            return compareContent(o2.getContent(), o1.getContent());\n        } else {\n            return compareContent(o1.getContent(), o2.getContent());\n        }\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/sort/RowHeaderSortHelper.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.sort;\n\nimport androidx.annotation.Nullable;\n\n/**\n * Created by cedricferry on 6/2/18.\n */\n\npublic class RowHeaderSortHelper {\n    @Nullable\n    private SortState mSortState;\n\n    public RowHeaderSortHelper() {\n    }\n\n    private void sortingStatusChanged(@Nullable SortState sortState) {\n        mSortState = sortState;\n        // TODO: Should we add an interface and listener and call listener when it is sorted?\n    }\n\n    public void setSortingStatus(@Nullable SortState status) {\n        mSortState = status;\n        sortingStatusChanged(status);\n    }\n\n    public void clearSortingStatus() {\n        mSortState = SortState.UNSORTED;\n    }\n\n    public boolean isSorting() {\n        return mSortState != SortState.UNSORTED;\n    }\n\n    @Nullable\n    public SortState getSortingStatus() {\n        return mSortState;\n    }\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/sort/SortState.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.sort;\n\n/**\n * Created by evrencoskun on 25.11.2017.\n */\n\npublic enum SortState {\n\n    /**\n     * Enumeration value indicating the items are sorted in increasing order.\n     * For example, the set <code>1, 4, 0</code> sorted in\n     * <code>ASCENDING</code> order is <code>0, 1, 4</code>.\n     */\n    ASCENDING,\n\n    /**\n     * Enumeration value indicating the items are sorted in decreasing order.\n     * For example, the set <code>1, 4, 0</code> sorted in\n     * <code>DESCENDING</code> order is <code>4, 1, 0</code>.\n     */\n    DESCENDING,\n\n    /**\n     * Enumeration value indicating the items are unordered.\n     * For example, the set <code>1, 4, 0</code> in\n     * <code>UNSORTED</code> order is <code>1, 4, 0</code>.\n     */\n    UNSORTED\n\n}\n"
  },
  {
    "path": "tableview/src/main/java/com/evrencoskun/tableview/util/TableViewUtils.java",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2021 Evren Coşkun\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\npackage com.evrencoskun.tableview.util;\n\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.recyclerview.widget.RecyclerView;\n\n/**\n * Created by evrencoskun on 18/09/2017.\n */\n\npublic class TableViewUtils {\n\n    /**\n     * Helps to force width value before calling requestLayout by the system.\n     */\n    public static void setWidth(@NonNull View view, int width) {\n        // Change width value from params\n        ((RecyclerView.LayoutParams) view.getLayoutParams()).width = width;\n\n        int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);\n        int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(view.getMeasuredHeight(), View\n                .MeasureSpec.EXACTLY);\n        view.measure(widthMeasureSpec, heightMeasureSpec);\n\n        view.requestLayout();\n    }\n\n}\n"
  },
  {
    "path": "tableview/src/main/res/drawable/cell_line_divider.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n ~ MIT License\n ~\n ~ Copyright (c) 2021 Evren Coşkun\n ~\n ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n ~ of this software and associated documentation files (the \"Software\"), to deal\n ~ in the Software without restriction, including without limitation the rights\n ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n ~ copies of the Software, and to permit persons to whom the Software is\n ~ furnished to do so, subject to the following conditions:\n ~\n ~ The above copyright notice and this permission notice shall be included in all\n ~ copies or substantial portions of the Software.\n ~\n ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n ~ SOFTWARE.\n  -->\n\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n       android:shape=\"rectangle\">\n    <size\n        android:width=\"1dp\"\n        android:height=\"1dp\"/>\n    <solid android:color=\"@color/table_view_default_separator_color\"/>\n</shape>\n"
  },
  {
    "path": "tableview/src/main/res/values/attrs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n ~ MIT License\n ~\n ~ Copyright (c) 2021 Evren Coşkun\n ~\n ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n ~ of this software and associated documentation files (the \"Software\"), to deal\n ~ in the Software without restriction, including without limitation the rights\n ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n ~ copies of the Software, and to permit persons to whom the Software is\n ~ furnished to do so, subject to the following conditions:\n ~\n ~ The above copyright notice and this permission notice shall be included in all\n ~ copies or substantial portions of the Software.\n ~\n ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n ~ SOFTWARE.\n  -->\n\n<resources>\n    <declare-styleable name=\"TableView\">\n        <attr name=\"row_header_width\" format=\"dimension\"/>\n        <attr name=\"column_header_height\" format=\"dimension\"/>\n        <attr name=\"selected_color\" format=\"color\"/>\n        <attr name=\"unselected_color\" format=\"color\"/>\n        <attr name=\"shadow_color\" format=\"color\"/>\n        <attr name=\"separator_color\" format=\"color\"/>\n        <attr name=\"show_vertical_separator\" format=\"boolean\"/>\n        <attr name=\"show_horizontal_separator\" format=\"boolean\"/>\n        <attr name=\"allow_click_inside_cell\" format=\"boolean\" />\n        <attr name=\"allow_click_inside_row_header\" format=\"boolean\" />\n        <attr name=\"allow_click_inside_column_header\" format=\"boolean\" />\n        <attr name=\"corner_view_location\">\n            <enum name=\"top_left\" value=\"0\"/>\n            <enum name=\"top_right\" value=\"1\"/>\n            <enum name=\"bottom_left\" value=\"2\"/>\n            <enum name=\"bottom_right\" value=\"3\"/>\n        </attr>\n        <attr name=\"reverse_layout\" format=\"boolean\" />\n    </declare-styleable>\n</resources>\n"
  },
  {
    "path": "tableview/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n ~ MIT License\n ~\n ~ Copyright (c) 2021 Evren Coşkun\n ~\n ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n ~ of this software and associated documentation files (the \"Software\"), to deal\n ~ in the Software without restriction, including without limitation the rights\n ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n ~ copies of the Software, and to permit persons to whom the Software is\n ~ furnished to do so, subject to the following conditions:\n ~\n ~ The above copyright notice and this permission notice shall be included in all\n ~ copies or substantial portions of the Software.\n ~\n ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n ~ SOFTWARE.\n  -->\n\n<resources>\n    <color name=\"table_view_default_separator_color\">#E7E7E7</color>\n    <color name=\"table_view_default_unselected_background_color\">#ffffff</color>\n    <color name=\"table_view_default_selected_background_color\">#fada65</color>\n    <color name=\"table_view_default_shadow_background_color\">#f2f2f2</color>\n</resources>\n"
  },
  {
    "path": "tableview/src/main/res/values/dimens.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n ~ MIT License\n ~\n ~ Copyright (c) 2021 Evren Coşkun\n ~\n ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n ~ of this software and associated documentation files (the \"Software\"), to deal\n ~ in the Software without restriction, including without limitation the rights\n ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n ~ copies of the Software, and to permit persons to whom the Software is\n ~ furnished to do so, subject to the following conditions:\n ~\n ~ The above copyright notice and this permission notice shall be included in all\n ~ copies or substantial portions of the Software.\n ~\n ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n ~ SOFTWARE.\n  -->\n\n<resources>\n    <dimen name=\"default_row_header_width\">55dp</dimen>\n    <dimen name=\"default_column_header_height\">55dp</dimen>\n</resources>\n"
  },
  {
    "path": "tableview/src/main/res/values/ids.xml",
    "content": "<!--\n  ~ MIT License\n  ~\n  ~ Copyright (c) 2021 Andrew Beck\n  ~\n  ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n  ~ of this software and associated documentation files (the \"Software\"), to deal\n  ~ in the Software without restriction, including without limitation the rights\n  ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n  ~ copies of the Software, and to permit persons to whom the Software is\n  ~ furnished to do so, subject to the following conditions:\n  ~\n  ~ The above copyright notice and this permission notice shall be included in all\n  ~ copies or substantial portions of the Software.\n  ~\n  ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n  ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n  ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n  ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n  ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n  ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n  ~ SOFTWARE.\n  -->\n\n<resources>\n    <item name=\"ColumnHeaderRecyclerView\" type=\"id\"/>\n    <item name=\"RowHeaderRecyclerView\" type=\"id\"/>\n    <item name=\"CellRecyclerView\" type=\"id\"/>\n</resources>\n"
  },
  {
    "path": "tableview/src/main/res/values/integers.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n ~ MIT License\n ~\n ~ Copyright (c) 2021 Evren Coşkun\n ~\n ~ Permission is hereby granted, free of charge, to any person obtaining a copy\n ~ of this software and associated documentation files (the \"Software\"), to deal\n ~ in the Software without restriction, including without limitation the rights\n ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n ~ copies of the Software, and to permit persons to whom the Software is\n ~ furnished to do so, subject to the following conditions:\n ~\n ~ The above copyright notice and this permission notice shall be included in all\n ~ copies or substantial portions of the Software.\n ~\n ~ THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n ~ SOFTWARE.\n  -->\n\n<resources>\n    <integer name=\"default_item_cache_size\">10</integer>\n</resources>\n"
  }
]