class DataTablesObservers {

    private final Workspace workspace;
    private final GraphModel graphModel;
    private final Set<ColumnObserver> columnObservers;
    private GraphObserver graphObserver;
    private TableObserver nodesTableObserver;
    private TableObserver edgesTableObserver;

    public DataTablesObservers(Workspace workspace) {
        this.workspace = workspace;
        this.graphModel = Lookup.getDefault().lookup(GraphController.class).getGraphModel(workspace);
        this.columnObservers = new HashSet<>();
    }

    public synchronized void initialize() {
        if (graphObserver != null) {
            return;
        }

        graphObserver = graphModel.createGraphObserver(graphModel.getGraph(), false);
        nodesTableObserver = graphModel.getNodeTable().createTableObserver(true);
        edgesTableObserver = graphModel.getEdgeTable().createTableObserver(true);

        for (Column column : graphModel.getNodeTable()) {
            createColumnObserver(column);
        }
        for (Column column : graphModel.getEdgeTable()) {
            createColumnObserver(column);
        }

        workspace.add(new LatestVisibleView(graphModel.getVisibleView()));
    }

    public synchronized void destroy() {
        if (graphObserver != null) {
            graphObserver.destroy();
            graphObserver = null;
        }
        if (nodesTableObserver != null) {
            nodesTableObserver.destroy();
            nodesTableObserver = null;
        }
        if (edgesTableObserver != null) {
            edgesTableObserver.destroy();
            edgesTableObserver = null;
        }

        for (ColumnObserver columnObserver : columnObservers) {
            columnObserver.destroy();
        }
        columnObservers.clear();
    }

    public boolean hasChanges() {
        if (graphObserver == null) {
            return false;//Not initialized
        }

        boolean hasChanges = graphObserver.hasGraphChanged();
        hasChanges = processTableObseverChanges(nodesTableObserver) || hasChanges;
        hasChanges = processTableObseverChanges(edgesTableObserver) || hasChanges;

        LatestVisibleView latestVisibleView = workspace.getLookup().lookup(LatestVisibleView.class);

        if (latestVisibleView.getView() != graphModel.getVisibleView()) {
            latestVisibleView.setView(graphModel.getVisibleView());
            hasChanges = true;
        }

        if (!hasChanges) {
            for (ColumnObserver columnObserver : columnObservers) {
                if (columnObserver.hasColumnChanged()) {
                    hasChanges = true;
                    break;
                }
            }
        }

        return hasChanges;
    }

    private boolean processTableObseverChanges(TableObserver observer) {<FILL_FUNCTION_BODY>}

    private void createColumnObserver(Column column) {
        ColumnObserver observer = column.createColumnObserver(false);
        columnObservers.add(observer);
    }

    /**
     * Used only for detecting changes in graph filters (visible view).
     */
    class LatestVisibleView {

        private GraphView view;

        public LatestVisibleView(GraphView view) {
            this.view = view;
        }

        public GraphView getView() {
            return view;
        }

        private void setView(GraphView view) {
            this.view = view;
        }
    }
}

        boolean hasChanges = false;
        if (observer.hasTableChanged()) {
            hasChanges = true;
            TableDiff diff = observer.getDiff();
            for (Column addedColumn : diff.getAddedColumns()) {
                createColumnObserver(addedColumn);
            }
            for (Column removedColumn : diff.getRemovedColumns()) {
                for (ColumnObserver columnObserver : columnObservers.toArray(new ColumnObserver[0])) {
                    if (columnObserver.getColumn() == removedColumn) {
                        columnObserver.destroy();
                        columnObservers.remove(columnObserver);
                    }
                }
            }
        }

        return hasChanges;
    
<no_super_class>